]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
Simplify Mod_ShadowMesh_* functions - removed support for every unused feature of...
[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 static int r_textureframe = 0; ///< used only by R_GetCurrentTexture
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_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_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_SAVE, "r_motionblur_averaging", "0.1", "sliding average reaction time for velocity (higher = slower adaption to change)"};
62 cvar_t r_motionblur_randomize = {CVAR_SAVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"};
63 cvar_t r_motionblur_minblur = {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_SAVE, "r_motionblur_maxblur", "0.9", "maxmimum amount of blur"};
65 cvar_t r_motionblur_velocityfactor = {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_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_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_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_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_SAVE, "r_motionblur_mousefactor_maxspeed", "50", "upper value of mouse acceleration when it reaches the peak factor into blur equation"};
71
72 // TODO do we want a r_equalize_entities cvar that works on all ents, or would that be a cheat?
73 cvar_t r_equalize_entities_fullbright = {CVAR_SAVE, "r_equalize_entities_fullbright", "0", "render fullbright entities by equalizing their lightness, not by not rendering light (DEPRECATED)"};
74 cvar_t r_equalize_entities_minambient = {CVAR_SAVE, "r_equalize_entities_minambient", "0.5", "light equalizing: ensure at least this ambient/diffuse ratio (DEPRECATED)"};
75 cvar_t r_equalize_entities_by = {CVAR_SAVE, "r_equalize_entities_by", "0.7", "light equalizing: exponent of dynamics compression (0 = no compression, 1 = full compression) (DEPRECATED)"};
76 cvar_t r_equalize_entities_to = {CVAR_SAVE, "r_equalize_entities_to", "0.8", "light equalizing: target light level (DEPRECATED)"};
77
78 cvar_t r_depthfirst = {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"};
79 cvar_t r_useinfinitefarclip = {CVAR_SAVE, "r_useinfinitefarclip", "1", "enables use of a special kind of projection matrix that has an extremely large farclip"};
80 cvar_t r_farclip_base = {0, "r_farclip_base", "65536", "farclip (furthest visible distance) for rendering when r_useinfinitefarclip is 0"};
81 cvar_t r_farclip_world = {0, "r_farclip_world", "2", "adds map size to farclip multiplied by this value"};
82 cvar_t r_nearclip = {0, "r_nearclip", "1", "distance from camera of nearclip plane" };
83 cvar_t r_deformvertexes = {0, "r_deformvertexes", "1", "allows use of deformvertexes in shader files (can be turned off to check performance impact)"};
84 cvar_t r_transparent = {0, "r_transparent", "1", "allows use of transparent surfaces (can be turned off to check performance impact)"};
85 cvar_t r_transparent_alphatocoverage = {0, "r_transparent_alphatocoverage", "1", "enables GL_ALPHA_TO_COVERAGE antialiasing technique on alphablend and alphatest surfaces when using vid_samples 2 or higher"};
86 cvar_t r_transparent_sortsurfacesbynearest = {0, "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"};
87 cvar_t r_transparent_useplanardistance = {0, "r_transparent_useplanardistance", "0", "sort transparent meshes by distance from view plane rather than spherical distance to the chosen point"};
88 cvar_t r_showoverdraw = {0, "r_showoverdraw", "0", "shows overlapping geometry"};
89 cvar_t r_showbboxes = {0, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
90 cvar_t r_showbboxes_client = { 0, "r_showbboxes_client", "0", "shows bounding boxes of clientside qc entities, value controls opacity scaling (1 = 10%,  10 = 100%)" };
91 cvar_t r_showsurfaces = {0, "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)"};
92 cvar_t r_showtris = {0, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
93 cvar_t r_shownormals = {0, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
94 cvar_t r_showlighting = {0, "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"};
95 cvar_t r_showcollisionbrushes = {0, "r_showcollisionbrushes", "0", "draws collision brushes in quake3 maps (mode 1), mode 2 disables rendering of world (trippy!)"};
96 cvar_t r_showcollisionbrushes_polygonfactor = {0, "r_showcollisionbrushes_polygonfactor", "-1", "expands outward the brush polygons a little bit, used to make collision brushes appear infront of walls"};
97 cvar_t r_showcollisionbrushes_polygonoffset = {0, "r_showcollisionbrushes_polygonoffset", "0", "nudges brush polygon depth in hardware depth units, used to make collision brushes appear infront of walls"};
98 cvar_t r_showdisabledepthtest = {0, "r_showdisabledepthtest", "0", "disables depth testing on r_show* cvars, allowing you to see what hidden geometry the graphics card is processing"};
99 cvar_t r_showspriteedges = {0, "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"};
100 cvar_t r_showparticleedges = {0, "r_showparticleedges", "0", "renders a debug outline to show the polygon shape of each particle, for debugging rendering bugs with specific view types"};
101 cvar_t r_drawportals = {0, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
102 cvar_t r_drawentities = {0, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
103 cvar_t r_draw2d = {0, "r_draw2d","1", "draw 2D stuff (dangerous to turn off)"};
104 cvar_t r_drawworld = {0, "r_drawworld","1", "draw world (most static stuff)"};
105 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1", "draw your weapon model"};
106 cvar_t r_drawexteriormodel = {0, "r_drawexteriormodel","1", "draw your player model (e.g. in chase cam, reflections)"};
107 cvar_t r_cullentities_trace = {0, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
108 cvar_t r_cullentities_trace_entityocclusion = { 0, "r_cullentities_trace_entityocclusion", "1", "check for occluding entities such as doors, not just world hull" };
109 cvar_t r_cullentities_trace_samples = {0, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling (in addition to center sample)"};
110 cvar_t r_cullentities_trace_tempentitysamples = {0, "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)"};
111 cvar_t r_cullentities_trace_enlarge = {0, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
112 cvar_t r_cullentities_trace_expand = {0, "r_cullentities_trace_expand", "0", "box expanded by this many units for entity culling"};
113 cvar_t r_cullentities_trace_pad = {0, "r_cullentities_trace_pad", "8", "accept traces that hit within this many units of the box"};
114 cvar_t r_cullentities_trace_delay = {0, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
115 cvar_t r_cullentities_trace_eyejitter = {0, "r_cullentities_trace_eyejitter", "16", "randomly offset rays from the eye by this much to reduce the odds of flickering"};
116 cvar_t r_sortentities = {0, "r_sortentities", "0", "sort entities before drawing (might be faster)"};
117 cvar_t r_speeds = {0, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
118 cvar_t r_fullbright = {0, "r_fullbright","0", "makes map very bright and renders faster"};
119
120 cvar_t r_fakelight = {0, "r_fakelight","0", "render 'fake' lighting instead of real lightmaps (DEPRECATED)"};
121 cvar_t r_fakelight_intensity = {0, "r_fakelight_intensity","0.75", "fakelight intensity modifier (DEPRECATED)"};
122 #define FAKELIGHT_ENABLED (r_fakelight.integer >= 2 || (r_fakelight.integer && r_refdef.scene.worldmodel && !r_refdef.scene.worldmodel->lit))
123
124 cvar_t r_fullbright_directed = {0, "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"};
125 cvar_t r_fullbright_directed_ambient = {0, "r_fullbright_directed_ambient", "0.5", "ambient light multiplier for directed fullbright"};
126 cvar_t r_fullbright_directed_diffuse = {0, "r_fullbright_directed_diffuse", "0.75", "diffuse light multiplier for directed fullbright"};
127 cvar_t r_fullbright_directed_pitch = {0, "r_fullbright_directed_pitch", "20", "constant pitch direction ('height') of the fake light source to use for fullbright"};
128 cvar_t r_fullbright_directed_pitch_relative = {0, "r_fullbright_directed_pitch_relative", "0", "whether r_fullbright_directed_pitch is interpreted as absolute (0) or relative (1) pitch"};
129
130 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1", "opacity of water polygons"};
131 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
132 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
133 cvar_t r_shadows = {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."};
134 cvar_t r_shadows_darken = {CVAR_SAVE, "r_shadows_darken", "0.5", "how much shadowed areas will be darkened"};
135 cvar_t r_shadows_throwdistance = {CVAR_SAVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
136 cvar_t r_shadows_throwdirection = {CVAR_SAVE, "r_shadows_throwdirection", "0 0 -1", "override throwing direction for r_shadows 2"};
137 cvar_t r_shadows_drawafterrtlighting = {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."};
138 cvar_t r_shadows_castfrombmodels = {CVAR_SAVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
139 cvar_t r_shadows_focus = {CVAR_SAVE, "r_shadows_focus", "0 0 0", "offset the shadowed area focus"};
140 cvar_t r_shadows_shadowmapscale = {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."};
141 cvar_t r_shadows_shadowmapbias = {CVAR_SAVE, "r_shadows_shadowmapbias", "-1", "sets shadowmap bias for fake shadows. -1 sets the value of r_shadow_shadowmapping_bias. Needs shadowmapping ON."};
142 cvar_t r_q1bsp_skymasking = {0, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
143 cvar_t r_polygonoffset_submodel_factor = {0, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
144 cvar_t r_polygonoffset_submodel_offset = {0, "r_polygonoffset_submodel_offset", "14", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
145 cvar_t r_polygonoffset_decals_factor = {0, "r_polygonoffset_decals_factor", "0", "biases depth values of decals to prevent z-fighting artifacts"};
146 cvar_t r_polygonoffset_decals_offset = {0, "r_polygonoffset_decals_offset", "-14", "biases depth values of decals to prevent z-fighting artifacts"};
147 cvar_t r_fog_exp2 = {0, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"};
148 cvar_t r_fog_clear = {0, "r_fog_clear", "1", "clears renderbuffer with fog color before render starts"};
149 cvar_t r_drawfog = {CVAR_SAVE, "r_drawfog", "1", "allows one to disable fog rendering"};
150 cvar_t r_transparentdepthmasking = {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"};
151 cvar_t r_transparent_sortmindist = {CVAR_SAVE, "r_transparent_sortmindist", "0", "lower distance limit for transparent sorting"};
152 cvar_t r_transparent_sortmaxdist = {CVAR_SAVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"};
153 cvar_t r_transparent_sortarraysize = {CVAR_SAVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"};
154 cvar_t r_celshading = {CVAR_SAVE, "r_celshading", "0", "cartoon-style light shading (OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9
155 cvar_t r_celoutlines = {CVAR_SAVE, "r_celoutlines", "0", "cartoon-style outlines (requires r_shadow_deferred; OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9
156
157 cvar_t gl_fogenable = {0, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
158 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
159 cvar_t gl_fogred = {0, "gl_fogred","0.3", "nehahra fog color red value (for Nehahra compatibility only)"};
160 cvar_t gl_foggreen = {0, "gl_foggreen","0.3", "nehahra fog color green value (for Nehahra compatibility only)"};
161 cvar_t gl_fogblue = {0, "gl_fogblue","0.3", "nehahra fog color blue value (for Nehahra compatibility only)"};
162 cvar_t gl_fogstart = {0, "gl_fogstart", "0", "nehahra fog start distance (for Nehahra compatibility only)"};
163 cvar_t gl_fogend = {0, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
164 cvar_t gl_skyclip = {0, "gl_skyclip", "4608", "nehahra farclip distance - the real fog end (for Nehahra compatibility only)"};
165
166 cvar_t r_texture_dds_load = {CVAR_SAVE, "r_texture_dds_load", "0", "load compressed dds/filename.dds texture instead of filename.tga, if the file exists (requires driver support)"};
167 cvar_t r_texture_dds_save = {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"};
168
169 cvar_t r_textureunits = {0, "r_textureunits", "32", "number of texture units to use in GL 1.1 and GL 1.3 rendering paths"};
170 static cvar_t gl_combine = {CVAR_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"};
171 static cvar_t r_glsl = {CVAR_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"};
172
173 cvar_t r_usedepthtextures = {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"};
174 cvar_t r_viewfbo = {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"};
175 cvar_t r_rendertarget_debug = {0, "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)"};
176 cvar_t r_viewscale = {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"};
177 cvar_t r_viewscale_fpsscaling = {CVAR_SAVE, "r_viewscale_fpsscaling", "0", "change resolution based on framerate"};
178 cvar_t r_viewscale_fpsscaling_min = {CVAR_SAVE, "r_viewscale_fpsscaling_min", "0.0625", "worst acceptable quality"};
179 cvar_t r_viewscale_fpsscaling_multiply = {CVAR_SAVE, "r_viewscale_fpsscaling_multiply", "5", "adjust quality up or down by the frametime difference from 1.0/target, multiplied by this factor"};
180 cvar_t r_viewscale_fpsscaling_stepsize = {CVAR_SAVE, "r_viewscale_fpsscaling_stepsize", "0.01", "smallest adjustment to hit the target framerate (this value prevents minute oscillations)"};
181 cvar_t r_viewscale_fpsscaling_stepmax = {CVAR_SAVE, "r_viewscale_fpsscaling_stepmax", "1.00", "largest adjustment to hit the target framerate (this value prevents wild overshooting of the estimate)"};
182 cvar_t r_viewscale_fpsscaling_target = {CVAR_SAVE, "r_viewscale_fpsscaling_target", "70", "desired framerate"};
183
184 cvar_t r_glsl_skeletal = {CVAR_SAVE, "r_glsl_skeletal", "1", "render skeletal models faster using a gpu-skinning technique"};
185 cvar_t r_glsl_deluxemapping = {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)"};
186 cvar_t r_glsl_offsetmapping = {CVAR_SAVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
187 cvar_t r_glsl_offsetmapping_steps = {CVAR_SAVE, "r_glsl_offsetmapping_steps", "2", "offset mapping steps (note: too high values may be not supported by your GPU)"};
188 cvar_t r_glsl_offsetmapping_reliefmapping = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
189 cvar_t r_glsl_offsetmapping_reliefmapping_steps = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_steps", "10", "relief mapping steps (note: too high values may be not supported by your GPU)"};
190 cvar_t r_glsl_offsetmapping_reliefmapping_refinesteps = {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)"};
191 cvar_t r_glsl_offsetmapping_scale = {CVAR_SAVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
192 cvar_t r_glsl_offsetmapping_lod = {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"};
193 cvar_t r_glsl_offsetmapping_lod_distance = {CVAR_SAVE, "r_glsl_offsetmapping_lod_distance", "32", "first LOD level distance, second level (-50% steps) is 2x of this, third (33%) - 3x etc."};
194 cvar_t r_glsl_postprocess = {CVAR_SAVE, "r_glsl_postprocess", "0", "use a GLSL postprocessing shader"};
195 cvar_t r_glsl_postprocess_uservec1 = {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)"};
196 cvar_t r_glsl_postprocess_uservec2 = {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)"};
197 cvar_t r_glsl_postprocess_uservec3 = {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)"};
198 cvar_t r_glsl_postprocess_uservec4 = {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)"};
199 cvar_t r_glsl_postprocess_uservec1_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec1_enable", "1", "enables postprocessing uservec1 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
200 cvar_t r_glsl_postprocess_uservec2_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec2_enable", "1", "enables postprocessing uservec2 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
201 cvar_t r_glsl_postprocess_uservec3_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec3_enable", "1", "enables postprocessing uservec3 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
202 cvar_t r_glsl_postprocess_uservec4_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec4_enable", "1", "enables postprocessing uservec4 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
203
204 cvar_t r_water = {CVAR_SAVE, "r_water", "0", "whether to use reflections and refraction on water surfaces (note: r_wateralpha must be set below 1)"};
205 cvar_t r_water_cameraentitiesonly = {CVAR_SAVE, "r_water_cameraentitiesonly", "0", "whether to only show QC-defined reflections/refractions (typically used for camera- or portal-like effects)"};
206 cvar_t r_water_clippingplanebias = {CVAR_SAVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
207 cvar_t r_water_resolutionmultiplier = {CVAR_SAVE, "r_water_resolutionmultiplier", "0.5", "multiplier for screen resolution when rendering refracted/reflected scenes, 1 is full quality, lower values are faster"};
208 cvar_t r_water_refractdistort = {CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
209 cvar_t r_water_reflectdistort = {CVAR_SAVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
210 cvar_t r_water_scissormode = {0, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
211 cvar_t r_water_lowquality = {0, "r_water_lowquality", "0", "special option to accelerate water rendering, 1 disables shadows and particles, 2 disables all dynamic lights"};
212 cvar_t r_water_hideplayer = {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"};
213
214 cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"};
215 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
216 cvar_t r_lerplightstyles = {CVAR_SAVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
217 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
218
219 cvar_t r_bloom = {CVAR_SAVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
220 cvar_t r_bloom_colorscale = {CVAR_SAVE, "r_bloom_colorscale", "1", "how bright the glow is"};
221
222 cvar_t r_bloom_brighten = {CVAR_SAVE, "r_bloom_brighten", "2", "how bright the glow is, after subtract/power"};
223 cvar_t r_bloom_blur = {CVAR_SAVE, "r_bloom_blur", "4", "how large the glow is"};
224 cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
225 cvar_t r_bloom_colorexponent = {CVAR_SAVE, "r_bloom_colorexponent", "1", "how exaggerated the glow is"};
226 cvar_t r_bloom_colorsubtract = {CVAR_SAVE, "r_bloom_colorsubtract", "0.125", "reduces bloom colors by a certain amount"};
227 cvar_t r_bloom_scenebrightness = {CVAR_SAVE, "r_bloom_scenebrightness", "1", "global rendering brightness when bloom is enabled"};
228
229 cvar_t r_hdr_scenebrightness = {CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
230 cvar_t r_hdr_glowintensity = {CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
231 cvar_t r_hdr_irisadaptation = {CVAR_SAVE, "r_hdr_irisadaptation", "0", "adjust scene brightness according to light intensity at player location"};
232 cvar_t r_hdr_irisadaptation_multiplier = {CVAR_SAVE, "r_hdr_irisadaptation_multiplier", "2", "brightness at which value will be 1.0"};
233 cvar_t r_hdr_irisadaptation_minvalue = {CVAR_SAVE, "r_hdr_irisadaptation_minvalue", "0.5", "minimum value that can result from multiplier / brightness"};
234 cvar_t r_hdr_irisadaptation_maxvalue = {CVAR_SAVE, "r_hdr_irisadaptation_maxvalue", "4", "maximum value that can result from multiplier / brightness"};
235 cvar_t r_hdr_irisadaptation_value = {0, "r_hdr_irisadaptation_value", "1", "current value as scenebrightness multiplier, changes continuously when irisadaptation is active"};
236 cvar_t r_hdr_irisadaptation_fade_up = {CVAR_SAVE, "r_hdr_irisadaptation_fade_up", "0.1", "fade rate at which value adjusts to darkness"};
237 cvar_t r_hdr_irisadaptation_fade_down = {CVAR_SAVE, "r_hdr_irisadaptation_fade_down", "0.5", "fade rate at which value adjusts to brightness"};
238 cvar_t r_hdr_irisadaptation_radius = {CVAR_SAVE, "r_hdr_irisadaptation_radius", "15", "lighting within this many units of the eye is averaged"};
239
240 cvar_t r_smoothnormals_areaweighting = {0, "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"};
241
242 cvar_t developer_texturelogging = {0, "developer_texturelogging", "0", "produces a textures.log file containing names of skins and map textures the engine tried to load"};
243
244 cvar_t gl_lightmaps = {0, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers), a value of 2 keeps normalmap shading"};
245
246 cvar_t r_test = {0, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
247
248 cvar_t r_batch_multidraw = {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)"};
249 cvar_t r_batch_multidraw_mintriangles = {CVAR_SAVE, "r_batch_multidraw_mintriangles", "0", "minimum number of triangles to activate multidraw path (copying small groups of triangles may be faster)"};
250 cvar_t r_batch_debugdynamicvertexpath = {CVAR_SAVE, "r_batch_debugdynamicvertexpath", "0", "force the dynamic batching code path for debugging purposes"};
251 cvar_t r_batch_dynamicbuffer = {CVAR_SAVE, "r_batch_dynamicbuffer", "0", "use vertex/index buffers for drawing dynamic and copytriangles batches"};
252
253 cvar_t r_glsl_saturation = {CVAR_SAVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
254 cvar_t r_glsl_saturation_redcompensate = {CVAR_SAVE, "r_glsl_saturation_redcompensate", "0", "a 'vampire sight' addition to desaturation effect, does compensation for red color, r_glsl_restart is required"};
255
256 cvar_t r_glsl_vertextextureblend_usebothalphas = {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."};
257
258 cvar_t r_framedatasize = {CVAR_SAVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"};
259 cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
260 {
261         {CVAR_SAVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"},
262         {CVAR_SAVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"},
263         {CVAR_SAVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"},
264         {CVAR_SAVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
265 };
266
267 extern cvar_t v_glslgamma_2d;
268
269 extern qboolean v_flipped_state;
270
271 r_framebufferstate_t r_fb;
272
273 /// shadow volume bsp struct with automatically growing nodes buffer
274 svbsp_t r_svbsp;
275
276 int r_uniformbufferalignment = 32; // dynamically updated to match GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
277
278 rtexture_t *r_texture_blanknormalmap;
279 rtexture_t *r_texture_white;
280 rtexture_t *r_texture_grey128;
281 rtexture_t *r_texture_black;
282 rtexture_t *r_texture_notexture;
283 rtexture_t *r_texture_whitecube;
284 rtexture_t *r_texture_normalizationcube;
285 rtexture_t *r_texture_fogattenuation;
286 rtexture_t *r_texture_fogheighttexture;
287 rtexture_t *r_texture_gammaramps;
288 unsigned int r_texture_gammaramps_serial;
289 //rtexture_t *r_texture_fogintensity;
290 rtexture_t *r_texture_reflectcube;
291
292 // TODO: hash lookups?
293 typedef struct cubemapinfo_s
294 {
295         char basename[64];
296         rtexture_t *texture;
297 }
298 cubemapinfo_t;
299
300 int r_texture_numcubemaps;
301 cubemapinfo_t *r_texture_cubemaps[MAX_CUBEMAPS];
302
303 unsigned int r_queries[MAX_OCCLUSION_QUERIES];
304 unsigned int r_numqueries;
305 unsigned int r_maxqueries;
306
307 typedef struct r_qwskincache_s
308 {
309         char name[MAX_QPATH];
310         skinframe_t *skinframe;
311 }
312 r_qwskincache_t;
313
314 static r_qwskincache_t *r_qwskincache;
315 static int r_qwskincache_size;
316
317 /// vertex coordinates for a quad that covers the screen exactly
318 extern const float r_screenvertex3f[12];
319 const float r_screenvertex3f[12] =
320 {
321         0, 0, 0,
322         1, 0, 0,
323         1, 1, 0,
324         0, 1, 0
325 };
326
327 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
328 {
329         int i;
330         for (i = 0;i < verts;i++)
331         {
332                 out[0] = in[0] * r;
333                 out[1] = in[1] * g;
334                 out[2] = in[2] * b;
335                 out[3] = in[3];
336                 in += 4;
337                 out += 4;
338         }
339 }
340
341 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
342 {
343         int i;
344         for (i = 0;i < verts;i++)
345         {
346                 out[0] = r;
347                 out[1] = g;
348                 out[2] = b;
349                 out[3] = a;
350                 out += 4;
351         }
352 }
353
354 // FIXME: move this to client?
355 void FOG_clear(void)
356 {
357         if (gamemode == GAME_NEHAHRA)
358         {
359                 Cvar_Set("gl_fogenable", "0");
360                 Cvar_Set("gl_fogdensity", "0.2");
361                 Cvar_Set("gl_fogred", "0.3");
362                 Cvar_Set("gl_foggreen", "0.3");
363                 Cvar_Set("gl_fogblue", "0.3");
364         }
365         r_refdef.fog_density = 0;
366         r_refdef.fog_red = 0;
367         r_refdef.fog_green = 0;
368         r_refdef.fog_blue = 0;
369         r_refdef.fog_alpha = 1;
370         r_refdef.fog_start = 0;
371         r_refdef.fog_end = 16384;
372         r_refdef.fog_height = 1<<30;
373         r_refdef.fog_fadedepth = 128;
374         memset(r_refdef.fog_height_texturename, 0, sizeof(r_refdef.fog_height_texturename));
375 }
376
377 static void R_BuildBlankTextures(void)
378 {
379         unsigned char data[4];
380         data[2] = 128; // normal X
381         data[1] = 128; // normal Y
382         data[0] = 255; // normal Z
383         data[3] = 255; // height
384         r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
385         data[0] = 255;
386         data[1] = 255;
387         data[2] = 255;
388         data[3] = 255;
389         r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
390         data[0] = 128;
391         data[1] = 128;
392         data[2] = 128;
393         data[3] = 255;
394         r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
395         data[0] = 0;
396         data[1] = 0;
397         data[2] = 0;
398         data[3] = 255;
399         r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
400 }
401
402 static void R_BuildNoTexture(void)
403 {
404         int x, y;
405         unsigned char pix[16][16][4];
406         // this makes a light grey/dark grey checkerboard texture
407         for (y = 0;y < 16;y++)
408         {
409                 for (x = 0;x < 16;x++)
410                 {
411                         if ((y < 8) ^ (x < 8))
412                         {
413                                 pix[y][x][0] = 128;
414                                 pix[y][x][1] = 128;
415                                 pix[y][x][2] = 128;
416                                 pix[y][x][3] = 255;
417                         }
418                         else
419                         {
420                                 pix[y][x][0] = 64;
421                                 pix[y][x][1] = 64;
422                                 pix[y][x][2] = 64;
423                                 pix[y][x][3] = 255;
424                         }
425                 }
426         }
427         r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, -1, NULL);
428 }
429
430 static void R_BuildWhiteCube(void)
431 {
432         unsigned char data[6*1*1*4];
433         memset(data, 255, sizeof(data));
434         r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
435 }
436
437 static void R_BuildNormalizationCube(void)
438 {
439         int x, y, side;
440         vec3_t v;
441         vec_t s, t, intensity;
442 #define NORMSIZE 64
443         unsigned char *data;
444         data = (unsigned char *)Mem_Alloc(tempmempool, 6*NORMSIZE*NORMSIZE*4);
445         for (side = 0;side < 6;side++)
446         {
447                 for (y = 0;y < NORMSIZE;y++)
448                 {
449                         for (x = 0;x < NORMSIZE;x++)
450                         {
451                                 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
452                                 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
453                                 switch(side)
454                                 {
455                                 default:
456                                 case 0:
457                                         v[0] = 1;
458                                         v[1] = -t;
459                                         v[2] = -s;
460                                         break;
461                                 case 1:
462                                         v[0] = -1;
463                                         v[1] = -t;
464                                         v[2] = s;
465                                         break;
466                                 case 2:
467                                         v[0] = s;
468                                         v[1] = 1;
469                                         v[2] = t;
470                                         break;
471                                 case 3:
472                                         v[0] = s;
473                                         v[1] = -1;
474                                         v[2] = -t;
475                                         break;
476                                 case 4:
477                                         v[0] = s;
478                                         v[1] = -t;
479                                         v[2] = 1;
480                                         break;
481                                 case 5:
482                                         v[0] = -s;
483                                         v[1] = -t;
484                                         v[2] = -1;
485                                         break;
486                                 }
487                                 intensity = 127.0f / sqrt(DotProduct(v, v));
488                                 data[((side*64+y)*64+x)*4+2] = (unsigned char)(128.0f + intensity * v[0]);
489                                 data[((side*64+y)*64+x)*4+1] = (unsigned char)(128.0f + intensity * v[1]);
490                                 data[((side*64+y)*64+x)*4+0] = (unsigned char)(128.0f + intensity * v[2]);
491                                 data[((side*64+y)*64+x)*4+3] = 255;
492                         }
493                 }
494         }
495         r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
496         Mem_Free(data);
497 }
498
499 static void R_BuildFogTexture(void)
500 {
501         int x, b;
502 #define FOGWIDTH 256
503         unsigned char data1[FOGWIDTH][4];
504         //unsigned char data2[FOGWIDTH][4];
505         double d, r, alpha;
506
507         r_refdef.fogmasktable_start = r_refdef.fog_start;
508         r_refdef.fogmasktable_alpha = r_refdef.fog_alpha;
509         r_refdef.fogmasktable_range = r_refdef.fogrange;
510         r_refdef.fogmasktable_density = r_refdef.fog_density;
511
512         r = r_refdef.fogmasktable_range / FOGMASKTABLEWIDTH;
513         for (x = 0;x < FOGMASKTABLEWIDTH;x++)
514         {
515                 d = (x * r - r_refdef.fogmasktable_start);
516                 if(developer_extra.integer)
517                         Con_DPrintf("%f ", d);
518                 d = max(0, d);
519                 if (r_fog_exp2.integer)
520                         alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d);
521                 else
522                         alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d);
523                 if(developer_extra.integer)
524                         Con_DPrintf(" : %f ", alpha);
525                 alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha;
526                 if(developer_extra.integer)
527                         Con_DPrintf(" = %f\n", alpha);
528                 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
529         }
530
531         for (x = 0;x < FOGWIDTH;x++)
532         {
533                 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
534                 data1[x][0] = b;
535                 data1[x][1] = b;
536                 data1[x][2] = b;
537                 data1[x][3] = 255;
538                 //data2[x][0] = 255 - b;
539                 //data2[x][1] = 255 - b;
540                 //data2[x][2] = 255 - b;
541                 //data2[x][3] = 255;
542         }
543         if (r_texture_fogattenuation)
544         {
545                 R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
546                 //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
547         }
548         else
549         {
550                 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
551                 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
552         }
553 }
554
555 static void R_BuildFogHeightTexture(void)
556 {
557         unsigned char *inpixels;
558         int size;
559         int x;
560         int y;
561         int j;
562         float c[4];
563         float f;
564         inpixels = NULL;
565         strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename));
566         if (r_refdef.fogheighttexturename[0])
567                 inpixels = loadimagepixelsbgra(r_refdef.fogheighttexturename, true, false, false, NULL);
568         if (!inpixels)
569         {
570                 r_refdef.fog_height_tablesize = 0;
571                 if (r_texture_fogheighttexture)
572                         R_FreeTexture(r_texture_fogheighttexture);
573                 r_texture_fogheighttexture = NULL;
574                 if (r_refdef.fog_height_table2d)
575                         Mem_Free(r_refdef.fog_height_table2d);
576                 r_refdef.fog_height_table2d = NULL;
577                 if (r_refdef.fog_height_table1d)
578                         Mem_Free(r_refdef.fog_height_table1d);
579                 r_refdef.fog_height_table1d = NULL;
580                 return;
581         }
582         size = image_width;
583         r_refdef.fog_height_tablesize = size;
584         r_refdef.fog_height_table1d = (unsigned char *)Mem_Alloc(r_main_mempool, size * 4);
585         r_refdef.fog_height_table2d = (unsigned char *)Mem_Alloc(r_main_mempool, size * size * 4);
586         memcpy(r_refdef.fog_height_table1d, inpixels, size * 4);
587         Mem_Free(inpixels);
588         // LordHavoc: now the magic - what is that table2d for?  it is a cooked
589         // average fog color table accounting for every fog layer between a point
590         // and the camera.  (Note: attenuation is handled separately!)
591         for (y = 0;y < size;y++)
592         {
593                 for (x = 0;x < size;x++)
594                 {
595                         Vector4Clear(c);
596                         f = 0;
597                         if (x < y)
598                         {
599                                 for (j = x;j <= y;j++)
600                                 {
601                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
602                                         f++;
603                                 }
604                         }
605                         else
606                         {
607                                 for (j = x;j >= y;j--)
608                                 {
609                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
610                                         f++;
611                                 }
612                         }
613                         f = 1.0f / f;
614                         r_refdef.fog_height_table2d[(y*size+x)*4+0] = (unsigned char)(c[0] * f);
615                         r_refdef.fog_height_table2d[(y*size+x)*4+1] = (unsigned char)(c[1] * f);
616                         r_refdef.fog_height_table2d[(y*size+x)*4+2] = (unsigned char)(c[2] * f);
617                         r_refdef.fog_height_table2d[(y*size+x)*4+3] = (unsigned char)(c[3] * f);
618                 }
619         }
620         r_texture_fogheighttexture = R_LoadTexture2D(r_main_texturepool, "fogheighttable", size, size, r_refdef.fog_height_table2d, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_CLAMP, -1, NULL);
621 }
622
623 //=======================================================================================================================================================
624
625 static const char *builtinshaderstrings[] =
626 {
627 #include "shader_glsl.h"
628 0
629 };
630
631 //=======================================================================================================================================================
632
633 typedef struct shaderpermutationinfo_s
634 {
635         const char *pretext;
636         const char *name;
637 }
638 shaderpermutationinfo_t;
639
640 typedef struct shadermodeinfo_s
641 {
642         const char *sourcebasename;
643         const char *extension;
644         const char **builtinshaderstrings;
645         const char *pretext;
646         const char *name;
647         char *filename;
648         char *builtinstring;
649         int builtincrc;
650 }
651 shadermodeinfo_t;
652
653 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
654 shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
655 {
656         {"#define USEDIFFUSE\n", " diffuse"},
657         {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
658         {"#define USEVIEWTINT\n", " viewtint"},
659         {"#define USECOLORMAPPING\n", " colormapping"},
660         {"#define USESATURATION\n", " saturation"},
661         {"#define USEFOGINSIDE\n", " foginside"},
662         {"#define USEFOGOUTSIDE\n", " fogoutside"},
663         {"#define USEFOGHEIGHTTEXTURE\n", " fogheighttexture"},
664         {"#define USEFOGALPHAHACK\n", " fogalphahack"},
665         {"#define USEGAMMARAMPS\n", " gammaramps"},
666         {"#define USECUBEFILTER\n", " cubefilter"},
667         {"#define USEGLOW\n", " glow"},
668         {"#define USEBLOOM\n", " bloom"},
669         {"#define USESPECULAR\n", " specular"},
670         {"#define USEPOSTPROCESSING\n", " postprocessing"},
671         {"#define USEREFLECTION\n", " reflection"},
672         {"#define USEOFFSETMAPPING\n", " offsetmapping"},
673         {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
674         {"#define USESHADOWMAP2D\n", " shadowmap2d"},
675         {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm
676         {"#define USESHADOWMAPORTHO\n", " shadowmaportho"},
677         {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
678         {"#define USEALPHAKILL\n", " alphakill"},
679         {"#define USEREFLECTCUBE\n", " reflectcube"},
680         {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"},
681         {"#define USEBOUNCEGRID\n", " bouncegrid"},
682         {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm
683         {"#define USETRIPPY\n", " trippy"},
684         {"#define USEDEPTHRGB\n", " depthrgb"},
685         {"#define USEALPHAGENVERTEX\n", " alphagenvertex"},
686         {"#define USESKELETAL\n", " skeletal"},
687         {"#define USEOCCLUDE\n", " occlude"}
688 };
689
690 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
691 shadermodeinfo_t shadermodeinfo[SHADERLANGUAGE_COUNT][SHADERMODE_COUNT] =
692 {
693         // SHADERLANGUAGE_GLSL
694         {
695                 {"combined", "glsl", builtinshaderstrings, "#define MODE_GENERIC\n", " generic"},
696                 {"combined", "glsl", builtinshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
697                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
698                 {"combined", "glsl", builtinshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
699                 {"combined", "glsl", builtinshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
700                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
701                 {"combined", "glsl", builtinshaderstrings, "#define MODE_FAKELIGHT\n", " fakelight"},
702                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
703                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
704                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
705                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
706                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
707                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
708                 {"combined", "glsl", builtinshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
709                 {"combined", "glsl", builtinshaderstrings, "#define MODE_WATER\n", " water"},
710                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
711                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
712         },
713 };
714
715 struct r_glsl_permutation_s;
716 typedef struct r_glsl_permutation_s
717 {
718         /// hash lookup data
719         struct r_glsl_permutation_s *hashnext;
720         unsigned int mode;
721         dpuint64 permutation;
722
723         /// indicates if we have tried compiling this permutation already
724         qboolean compiled;
725         /// 0 if compilation failed
726         int program;
727         // texture units assigned to each detected uniform
728         int tex_Texture_First;
729         int tex_Texture_Second;
730         int tex_Texture_GammaRamps;
731         int tex_Texture_Normal;
732         int tex_Texture_Color;
733         int tex_Texture_Gloss;
734         int tex_Texture_Glow;
735         int tex_Texture_SecondaryNormal;
736         int tex_Texture_SecondaryColor;
737         int tex_Texture_SecondaryGloss;
738         int tex_Texture_SecondaryGlow;
739         int tex_Texture_Pants;
740         int tex_Texture_Shirt;
741         int tex_Texture_FogHeightTexture;
742         int tex_Texture_FogMask;
743         int tex_Texture_Lightmap;
744         int tex_Texture_Deluxemap;
745         int tex_Texture_Attenuation;
746         int tex_Texture_Cube;
747         int tex_Texture_Refraction;
748         int tex_Texture_Reflection;
749         int tex_Texture_ShadowMap2D;
750         int tex_Texture_CubeProjection;
751         int tex_Texture_ScreenNormalMap;
752         int tex_Texture_ScreenDiffuse;
753         int tex_Texture_ScreenSpecular;
754         int tex_Texture_ReflectMask;
755         int tex_Texture_ReflectCube;
756         int tex_Texture_BounceGrid;
757         /// locations of detected uniforms in program object, or -1 if not found
758         int loc_Texture_First;
759         int loc_Texture_Second;
760         int loc_Texture_GammaRamps;
761         int loc_Texture_Normal;
762         int loc_Texture_Color;
763         int loc_Texture_Gloss;
764         int loc_Texture_Glow;
765         int loc_Texture_SecondaryNormal;
766         int loc_Texture_SecondaryColor;
767         int loc_Texture_SecondaryGloss;
768         int loc_Texture_SecondaryGlow;
769         int loc_Texture_Pants;
770         int loc_Texture_Shirt;
771         int loc_Texture_FogHeightTexture;
772         int loc_Texture_FogMask;
773         int loc_Texture_Lightmap;
774         int loc_Texture_Deluxemap;
775         int loc_Texture_Attenuation;
776         int loc_Texture_Cube;
777         int loc_Texture_Refraction;
778         int loc_Texture_Reflection;
779         int loc_Texture_ShadowMap2D;
780         int loc_Texture_CubeProjection;
781         int loc_Texture_ScreenNormalMap;
782         int loc_Texture_ScreenDiffuse;
783         int loc_Texture_ScreenSpecular;
784         int loc_Texture_ReflectMask;
785         int loc_Texture_ReflectCube;
786         int loc_Texture_BounceGrid;
787         int loc_Alpha;
788         int loc_BloomBlur_Parameters;
789         int loc_ClientTime;
790         int loc_Color_Ambient;
791         int loc_Color_Diffuse;
792         int loc_Color_Specular;
793         int loc_Color_Glow;
794         int loc_Color_Pants;
795         int loc_Color_Shirt;
796         int loc_DeferredColor_Ambient;
797         int loc_DeferredColor_Diffuse;
798         int loc_DeferredColor_Specular;
799         int loc_DeferredMod_Diffuse;
800         int loc_DeferredMod_Specular;
801         int loc_DistortScaleRefractReflect;
802         int loc_EyePosition;
803         int loc_FogColor;
804         int loc_FogHeightFade;
805         int loc_FogPlane;
806         int loc_FogPlaneViewDist;
807         int loc_FogRangeRecip;
808         int loc_LightColor;
809         int loc_LightDir;
810         int loc_LightPosition;
811         int loc_OffsetMapping_ScaleSteps;
812         int loc_OffsetMapping_LodDistance;
813         int loc_OffsetMapping_Bias;
814         int loc_PixelSize;
815         int loc_ReflectColor;
816         int loc_ReflectFactor;
817         int loc_ReflectOffset;
818         int loc_RefractColor;
819         int loc_Saturation;
820         int loc_ScreenCenterRefractReflect;
821         int loc_ScreenScaleRefractReflect;
822         int loc_ScreenToDepth;
823         int loc_ShadowMap_Parameters;
824         int loc_ShadowMap_TextureScale;
825         int loc_SpecularPower;
826         int loc_Skeletal_Transform12;
827         int loc_UserVec1;
828         int loc_UserVec2;
829         int loc_UserVec3;
830         int loc_UserVec4;
831         int loc_ViewTintColor;
832         int loc_ViewToLight;
833         int loc_ModelToLight;
834         int loc_TexMatrix;
835         int loc_BackgroundTexMatrix;
836         int loc_ModelViewProjectionMatrix;
837         int loc_ModelViewMatrix;
838         int loc_PixelToScreenTexCoord;
839         int loc_ModelToReflectCube;
840         int loc_ShadowMapMatrix;
841         int loc_BloomColorSubtract;
842         int loc_NormalmapScrollBlend;
843         int loc_BounceGridMatrix;
844         int loc_BounceGridIntensity;
845         /// uniform block bindings
846         int ubibind_Skeletal_Transform12_UniformBlock;
847         /// uniform block indices
848         int ubiloc_Skeletal_Transform12_UniformBlock;
849 }
850 r_glsl_permutation_t;
851
852 #define SHADERPERMUTATION_HASHSIZE 256
853
854
855 // non-degradable "lightweight" shader parameters to keep the permutations simpler
856 // these can NOT degrade! only use for simple stuff
857 enum
858 {
859         SHADERSTATICPARM_SATURATION_REDCOMPENSATE = 0, ///< red compensation filter for saturation
860         SHADERSTATICPARM_EXACTSPECULARMATH = 1, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
861         SHADERSTATICPARM_POSTPROCESS_USERVEC1 = 2, ///< postprocess uservec1 is enabled
862         SHADERSTATICPARM_POSTPROCESS_USERVEC2 = 3, ///< postprocess uservec2 is enabled
863         SHADERSTATICPARM_POSTPROCESS_USERVEC3 = 4, ///< postprocess uservec3 is enabled
864         SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5,  ///< postprocess uservec4 is enabled
865         SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending
866         SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7,  ///< LOD for offsetmapping
867         SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1
868         SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2
869         SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
870         SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
871         SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
872         SHADERSTATICPARM_FXAA = 13 ///< fast approximate anti aliasing
873 };
874 #define SHADERSTATICPARMS_COUNT 14
875
876 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
877 static int shaderstaticparms_count = 0;
878
879 static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0};
880 #define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F))
881
882 extern qboolean r_shadow_shadowmapsampler;
883 extern int r_shadow_shadowmappcf;
884 qboolean R_CompileShader_CheckStaticParms(void)
885 {
886         static int r_compileshader_staticparms_save[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5];
887         memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
888         memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
889
890         // detect all
891         if (r_glsl_saturation_redcompensate.integer)
892                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SATURATION_REDCOMPENSATE);
893         if (r_glsl_vertextextureblend_usebothalphas.integer)
894                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS);
895         if (r_shadow_glossexact.integer)
896                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_EXACTSPECULARMATH);
897         if (r_glsl_postprocess.integer)
898         {
899                 if (r_glsl_postprocess_uservec1_enable.integer)
900                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC1);
901                 if (r_glsl_postprocess_uservec2_enable.integer)
902                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC2);
903                 if (r_glsl_postprocess_uservec3_enable.integer)
904                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC3);
905                 if (r_glsl_postprocess_uservec4_enable.integer)
906                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
907         }
908         if (r_fxaa.integer)
909                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_FXAA);
910         if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
911                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
912
913         if (r_shadow_shadowmapsampler)
914                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER);
915         if (r_shadow_shadowmappcf > 1)
916                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2);
917         else if (r_shadow_shadowmappcf)
918                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1);
919         if (r_celshading.integer)
920                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING);
921         if (r_celoutlines.integer)
922                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES);
923
924         return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
925 }
926
927 #define R_COMPILESHADER_STATICPARM_EMIT(p, n) \
928         if(r_compileshader_staticparms[(p) >> 5] & (1 << ((p) & 0x1F))) \
929                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \
930         else \
931                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n"
932 static void R_CompileShader_AddStaticParms(unsigned int mode, dpuint64 permutation)
933 {
934         shaderstaticparms_count = 0;
935
936         // emit all
937         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SATURATION_REDCOMPENSATE, "SATURATION_REDCOMPENSATE");
938         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_EXACTSPECULARMATH, "USEEXACTSPECULARMATH");
939         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC1, "USERVEC1");
940         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC2, "USERVEC2");
941         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC3, "USERVEC3");
942         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4");
943         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS");
944         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD");
945         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1");
946         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2");
947         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
948         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
949         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
950         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
951 }
952
953 /// information about each possible shader permutation
954 r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
955 /// currently selected permutation
956 r_glsl_permutation_t *r_glsl_permutation;
957 /// storage for permutations linked in the hash table
958 memexpandablearray_t r_glsl_permutationarray;
959
960 static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, dpuint64 permutation)
961 {
962         //unsigned int hashdepth = 0;
963         unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
964         r_glsl_permutation_t *p;
965         for (p = r_glsl_permutationhash[mode][hashindex];p;p = p->hashnext)
966         {
967                 if (p->mode == mode && p->permutation == permutation)
968                 {
969                         //if (hashdepth > 10)
970                         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
971                         return p;
972                 }
973                 //hashdepth++;
974         }
975         p = (r_glsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_glsl_permutationarray);
976         p->mode = mode;
977         p->permutation = permutation;
978         p->hashnext = r_glsl_permutationhash[mode][hashindex];
979         r_glsl_permutationhash[mode][hashindex] = p;
980         //if (hashdepth > 10)
981         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
982         return p;
983 }
984
985 static char *R_ShaderStrCat(const char **strings)
986 {
987         char *string, *s;
988         const char **p = strings;
989         const char *t;
990         size_t len = 0;
991         for (p = strings;(t = *p);p++)
992                 len += strlen(t);
993         len++;
994         s = string = (char *)Mem_Alloc(r_main_mempool, len);
995         len = 0;
996         for (p = strings;(t = *p);p++)
997         {
998                 len = strlen(t);
999                 memcpy(s, t, len);
1000                 s += len;
1001         }
1002         *s = 0;
1003         return string;
1004 }
1005
1006 static char *R_ShaderStrCat(const char **strings);
1007 static void R_InitShaderModeInfo(void)
1008 {
1009         int i, language;
1010         shadermodeinfo_t *modeinfo;
1011         // 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)
1012         for (language = 0; language < SHADERLANGUAGE_COUNT; language++)
1013         {
1014                 for (i = 0; i < SHADERMODE_COUNT; i++)
1015                 {
1016                         char filename[MAX_QPATH];
1017                         modeinfo = &shadermodeinfo[language][i];
1018                         modeinfo->builtinstring = R_ShaderStrCat(modeinfo->builtinshaderstrings);
1019                         modeinfo->builtincrc = CRC_Block((const unsigned char *)modeinfo->builtinstring, strlen(modeinfo->builtinstring));
1020                         dpsnprintf(filename, sizeof(filename), "%s/%s_crc%i.%s", modeinfo->extension, modeinfo->sourcebasename, modeinfo->builtincrc, modeinfo->extension);
1021                         modeinfo->filename = Mem_strdup(r_main_mempool, filename);
1022                 }
1023         }
1024 }
1025
1026 static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qboolean printfromdisknotice, qboolean builtinonly)
1027 {
1028         char *shaderstring;
1029         // if the mode has no filename we have to return the builtin string
1030         if (builtinonly || !modeinfo->filename)
1031                 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1032         // note that FS_LoadFile appends a 0 byte to make it a valid string
1033         shaderstring = (char *)FS_LoadFile(modeinfo->filename, r_main_mempool, false, NULL);
1034         if (shaderstring)
1035         {
1036                 if (printfromdisknotice)
1037                         Con_DPrintf("Loading shaders from file %s...\n", modeinfo->filename);
1038                 return shaderstring;
1039         }
1040         // fall back to builtinstring
1041         return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1042 }
1043
1044 static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, dpuint64 permutation)
1045 {
1046         int i;
1047         int ubibind;
1048         int sampler;
1049         shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode];
1050         char *sourcestring;
1051         char permutationname[256];
1052         int vertstrings_count = 0;
1053         int geomstrings_count = 0;
1054         int fragstrings_count = 0;
1055         const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1056         const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1057         const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1058
1059         if (p->compiled)
1060                 return;
1061         p->compiled = true;
1062         p->program = 0;
1063
1064         permutationname[0] = 0;
1065         sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false);
1066
1067         strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
1068
1069         // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object)
1070         if(vid.support.glshaderversion >= 140)
1071         {
1072                 vertstrings_list[vertstrings_count++] = "#version 140\n";
1073                 geomstrings_list[geomstrings_count++] = "#version 140\n";
1074                 fragstrings_list[fragstrings_count++] = "#version 140\n";
1075                 vertstrings_list[vertstrings_count++] = "#define GLSL140\n";
1076                 geomstrings_list[geomstrings_count++] = "#define GLSL140\n";
1077                 fragstrings_list[fragstrings_count++] = "#define GLSL140\n";
1078         }
1079         // if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad)
1080         else if(vid.support.glshaderversion >= 130)
1081         {
1082                 vertstrings_list[vertstrings_count++] = "#version 130\n";
1083                 geomstrings_list[geomstrings_count++] = "#version 130\n";
1084                 fragstrings_list[fragstrings_count++] = "#version 130\n";
1085                 vertstrings_list[vertstrings_count++] = "#define GLSL130\n";
1086                 geomstrings_list[geomstrings_count++] = "#define GLSL130\n";
1087                 fragstrings_list[fragstrings_count++] = "#define GLSL130\n";
1088         }
1089         // if we can do #version 120, we should (this adds the invariant keyword)
1090         else if(vid.support.glshaderversion >= 120)
1091         {
1092                 vertstrings_list[vertstrings_count++] = "#version 120\n";
1093                 geomstrings_list[geomstrings_count++] = "#version 120\n";
1094                 fragstrings_list[fragstrings_count++] = "#version 120\n";
1095                 vertstrings_list[vertstrings_count++] = "#define GLSL120\n";
1096                 geomstrings_list[geomstrings_count++] = "#define GLSL120\n";
1097                 fragstrings_list[fragstrings_count++] = "#define GLSL120\n";
1098         }
1099         // GLES also adds several things from GLSL120
1100         switch(vid.renderpath)
1101         {
1102         case RENDERPATH_GLES2:
1103                 vertstrings_list[vertstrings_count++] = "#define GLES\n";
1104                 geomstrings_list[geomstrings_count++] = "#define GLES\n";
1105                 fragstrings_list[fragstrings_count++] = "#define GLES\n";
1106                 break;
1107         default:
1108                 break;
1109         }
1110
1111         // the first pretext is which type of shader to compile as
1112         // (later these will all be bound together as a program object)
1113         vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
1114         geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
1115         fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
1116
1117         // the second pretext is the mode (for example a light source)
1118         vertstrings_list[vertstrings_count++] = modeinfo->pretext;
1119         geomstrings_list[geomstrings_count++] = modeinfo->pretext;
1120         fragstrings_list[fragstrings_count++] = modeinfo->pretext;
1121         strlcat(permutationname, modeinfo->name, sizeof(permutationname));
1122
1123         // now add all the permutation pretexts
1124         for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1125         {
1126                 if (permutation & (1ll<<i))
1127                 {
1128                         vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
1129                         geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
1130                         fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
1131                         strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
1132                 }
1133                 else
1134                 {
1135                         // keep line numbers correct
1136                         vertstrings_list[vertstrings_count++] = "\n";
1137                         geomstrings_list[geomstrings_count++] = "\n";
1138                         fragstrings_list[fragstrings_count++] = "\n";
1139                 }
1140         }
1141
1142         // add static parms
1143         R_CompileShader_AddStaticParms(mode, permutation);
1144         memcpy((char *)(vertstrings_list + vertstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1145         vertstrings_count += shaderstaticparms_count;
1146         memcpy((char *)(geomstrings_list + geomstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1147         geomstrings_count += shaderstaticparms_count;
1148         memcpy((char *)(fragstrings_list + fragstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1149         fragstrings_count += shaderstaticparms_count;
1150
1151         // now append the shader text itself
1152         vertstrings_list[vertstrings_count++] = sourcestring;
1153         geomstrings_list[geomstrings_count++] = sourcestring;
1154         fragstrings_list[fragstrings_count++] = sourcestring;
1155
1156         // compile the shader program
1157         if (vertstrings_count + geomstrings_count + fragstrings_count)
1158                 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1159         if (p->program)
1160         {
1161                 CHECKGLERROR
1162                 qglUseProgram(p->program);CHECKGLERROR
1163                 // look up all the uniform variable names we care about, so we don't
1164                 // have to look them up every time we set them
1165
1166 #if 0
1167                 // debugging aid
1168                 {
1169                         GLint activeuniformindex = 0;
1170                         GLint numactiveuniforms = 0;
1171                         char uniformname[128];
1172                         GLsizei uniformnamelength = 0;
1173                         GLint uniformsize = 0;
1174                         GLenum uniformtype = 0;
1175                         memset(uniformname, 0, sizeof(uniformname));
1176                         qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms);
1177                         Con_Printf("Shader has %i uniforms\n", numactiveuniforms);
1178                         for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++)
1179                         {
1180                                 qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname);
1181                                 Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype);
1182                         }
1183                 }
1184 #endif
1185
1186                 p->loc_Texture_First              = qglGetUniformLocation(p->program, "Texture_First");
1187                 p->loc_Texture_Second             = qglGetUniformLocation(p->program, "Texture_Second");
1188                 p->loc_Texture_GammaRamps         = qglGetUniformLocation(p->program, "Texture_GammaRamps");
1189                 p->loc_Texture_Normal             = qglGetUniformLocation(p->program, "Texture_Normal");
1190                 p->loc_Texture_Color              = qglGetUniformLocation(p->program, "Texture_Color");
1191                 p->loc_Texture_Gloss              = qglGetUniformLocation(p->program, "Texture_Gloss");
1192                 p->loc_Texture_Glow               = qglGetUniformLocation(p->program, "Texture_Glow");
1193                 p->loc_Texture_SecondaryNormal    = qglGetUniformLocation(p->program, "Texture_SecondaryNormal");
1194                 p->loc_Texture_SecondaryColor     = qglGetUniformLocation(p->program, "Texture_SecondaryColor");
1195                 p->loc_Texture_SecondaryGloss     = qglGetUniformLocation(p->program, "Texture_SecondaryGloss");
1196                 p->loc_Texture_SecondaryGlow      = qglGetUniformLocation(p->program, "Texture_SecondaryGlow");
1197                 p->loc_Texture_Pants              = qglGetUniformLocation(p->program, "Texture_Pants");
1198                 p->loc_Texture_Shirt              = qglGetUniformLocation(p->program, "Texture_Shirt");
1199                 p->loc_Texture_FogHeightTexture   = qglGetUniformLocation(p->program, "Texture_FogHeightTexture");
1200                 p->loc_Texture_FogMask            = qglGetUniformLocation(p->program, "Texture_FogMask");
1201                 p->loc_Texture_Lightmap           = qglGetUniformLocation(p->program, "Texture_Lightmap");
1202                 p->loc_Texture_Deluxemap          = qglGetUniformLocation(p->program, "Texture_Deluxemap");
1203                 p->loc_Texture_Attenuation        = qglGetUniformLocation(p->program, "Texture_Attenuation");
1204                 p->loc_Texture_Cube               = qglGetUniformLocation(p->program, "Texture_Cube");
1205                 p->loc_Texture_Refraction         = qglGetUniformLocation(p->program, "Texture_Refraction");
1206                 p->loc_Texture_Reflection         = qglGetUniformLocation(p->program, "Texture_Reflection");
1207                 p->loc_Texture_ShadowMap2D        = qglGetUniformLocation(p->program, "Texture_ShadowMap2D");
1208                 p->loc_Texture_CubeProjection     = qglGetUniformLocation(p->program, "Texture_CubeProjection");
1209                 p->loc_Texture_ScreenNormalMap    = qglGetUniformLocation(p->program, "Texture_ScreenNormalMap");
1210                 p->loc_Texture_ScreenDiffuse      = qglGetUniformLocation(p->program, "Texture_ScreenDiffuse");
1211                 p->loc_Texture_ScreenSpecular     = qglGetUniformLocation(p->program, "Texture_ScreenSpecular");
1212                 p->loc_Texture_ReflectMask        = qglGetUniformLocation(p->program, "Texture_ReflectMask");
1213                 p->loc_Texture_ReflectCube        = qglGetUniformLocation(p->program, "Texture_ReflectCube");
1214                 p->loc_Texture_BounceGrid         = qglGetUniformLocation(p->program, "Texture_BounceGrid");
1215                 p->loc_Alpha                      = qglGetUniformLocation(p->program, "Alpha");
1216                 p->loc_BloomBlur_Parameters       = qglGetUniformLocation(p->program, "BloomBlur_Parameters");
1217                 p->loc_ClientTime                 = qglGetUniformLocation(p->program, "ClientTime");
1218                 p->loc_Color_Ambient              = qglGetUniformLocation(p->program, "Color_Ambient");
1219                 p->loc_Color_Diffuse              = qglGetUniformLocation(p->program, "Color_Diffuse");
1220                 p->loc_Color_Specular             = qglGetUniformLocation(p->program, "Color_Specular");
1221                 p->loc_Color_Glow                 = qglGetUniformLocation(p->program, "Color_Glow");
1222                 p->loc_Color_Pants                = qglGetUniformLocation(p->program, "Color_Pants");
1223                 p->loc_Color_Shirt                = qglGetUniformLocation(p->program, "Color_Shirt");
1224                 p->loc_DeferredColor_Ambient      = qglGetUniformLocation(p->program, "DeferredColor_Ambient");
1225                 p->loc_DeferredColor_Diffuse      = qglGetUniformLocation(p->program, "DeferredColor_Diffuse");
1226                 p->loc_DeferredColor_Specular     = qglGetUniformLocation(p->program, "DeferredColor_Specular");
1227                 p->loc_DeferredMod_Diffuse        = qglGetUniformLocation(p->program, "DeferredMod_Diffuse");
1228                 p->loc_DeferredMod_Specular       = qglGetUniformLocation(p->program, "DeferredMod_Specular");
1229                 p->loc_DistortScaleRefractReflect = qglGetUniformLocation(p->program, "DistortScaleRefractReflect");
1230                 p->loc_EyePosition                = qglGetUniformLocation(p->program, "EyePosition");
1231                 p->loc_FogColor                   = qglGetUniformLocation(p->program, "FogColor");
1232                 p->loc_FogHeightFade              = qglGetUniformLocation(p->program, "FogHeightFade");
1233                 p->loc_FogPlane                   = qglGetUniformLocation(p->program, "FogPlane");
1234                 p->loc_FogPlaneViewDist           = qglGetUniformLocation(p->program, "FogPlaneViewDist");
1235                 p->loc_FogRangeRecip              = qglGetUniformLocation(p->program, "FogRangeRecip");
1236                 p->loc_LightColor                 = qglGetUniformLocation(p->program, "LightColor");
1237                 p->loc_LightDir                   = qglGetUniformLocation(p->program, "LightDir");
1238                 p->loc_LightPosition              = qglGetUniformLocation(p->program, "LightPosition");
1239                 p->loc_OffsetMapping_ScaleSteps   = qglGetUniformLocation(p->program, "OffsetMapping_ScaleSteps");
1240                 p->loc_OffsetMapping_LodDistance  = qglGetUniformLocation(p->program, "OffsetMapping_LodDistance");
1241                 p->loc_OffsetMapping_Bias         = qglGetUniformLocation(p->program, "OffsetMapping_Bias");
1242                 p->loc_PixelSize                  = qglGetUniformLocation(p->program, "PixelSize");
1243                 p->loc_ReflectColor               = qglGetUniformLocation(p->program, "ReflectColor");
1244                 p->loc_ReflectFactor              = qglGetUniformLocation(p->program, "ReflectFactor");
1245                 p->loc_ReflectOffset              = qglGetUniformLocation(p->program, "ReflectOffset");
1246                 p->loc_RefractColor               = qglGetUniformLocation(p->program, "RefractColor");
1247                 p->loc_Saturation                 = qglGetUniformLocation(p->program, "Saturation");
1248                 p->loc_ScreenCenterRefractReflect = qglGetUniformLocation(p->program, "ScreenCenterRefractReflect");
1249                 p->loc_ScreenScaleRefractReflect  = qglGetUniformLocation(p->program, "ScreenScaleRefractReflect");
1250                 p->loc_ScreenToDepth              = qglGetUniformLocation(p->program, "ScreenToDepth");
1251                 p->loc_ShadowMap_Parameters       = qglGetUniformLocation(p->program, "ShadowMap_Parameters");
1252                 p->loc_ShadowMap_TextureScale     = qglGetUniformLocation(p->program, "ShadowMap_TextureScale");
1253                 p->loc_SpecularPower              = qglGetUniformLocation(p->program, "SpecularPower");
1254                 p->loc_UserVec1                   = qglGetUniformLocation(p->program, "UserVec1");
1255                 p->loc_UserVec2                   = qglGetUniformLocation(p->program, "UserVec2");
1256                 p->loc_UserVec3                   = qglGetUniformLocation(p->program, "UserVec3");
1257                 p->loc_UserVec4                   = qglGetUniformLocation(p->program, "UserVec4");
1258                 p->loc_ViewTintColor              = qglGetUniformLocation(p->program, "ViewTintColor");
1259                 p->loc_ViewToLight                = qglGetUniformLocation(p->program, "ViewToLight");
1260                 p->loc_ModelToLight               = qglGetUniformLocation(p->program, "ModelToLight");
1261                 p->loc_TexMatrix                  = qglGetUniformLocation(p->program, "TexMatrix");
1262                 p->loc_BackgroundTexMatrix        = qglGetUniformLocation(p->program, "BackgroundTexMatrix");
1263                 p->loc_ModelViewMatrix            = qglGetUniformLocation(p->program, "ModelViewMatrix");
1264                 p->loc_ModelViewProjectionMatrix  = qglGetUniformLocation(p->program, "ModelViewProjectionMatrix");
1265                 p->loc_PixelToScreenTexCoord      = qglGetUniformLocation(p->program, "PixelToScreenTexCoord");
1266                 p->loc_ModelToReflectCube         = qglGetUniformLocation(p->program, "ModelToReflectCube");
1267                 p->loc_ShadowMapMatrix            = qglGetUniformLocation(p->program, "ShadowMapMatrix");
1268                 p->loc_BloomColorSubtract         = qglGetUniformLocation(p->program, "BloomColorSubtract");
1269                 p->loc_NormalmapScrollBlend       = qglGetUniformLocation(p->program, "NormalmapScrollBlend");
1270                 p->loc_BounceGridMatrix           = qglGetUniformLocation(p->program, "BounceGridMatrix");
1271                 p->loc_BounceGridIntensity        = qglGetUniformLocation(p->program, "BounceGridIntensity");
1272                 // initialize the samplers to refer to the texture units we use
1273                 p->tex_Texture_First = -1;
1274                 p->tex_Texture_Second = -1;
1275                 p->tex_Texture_GammaRamps = -1;
1276                 p->tex_Texture_Normal = -1;
1277                 p->tex_Texture_Color = -1;
1278                 p->tex_Texture_Gloss = -1;
1279                 p->tex_Texture_Glow = -1;
1280                 p->tex_Texture_SecondaryNormal = -1;
1281                 p->tex_Texture_SecondaryColor = -1;
1282                 p->tex_Texture_SecondaryGloss = -1;
1283                 p->tex_Texture_SecondaryGlow = -1;
1284                 p->tex_Texture_Pants = -1;
1285                 p->tex_Texture_Shirt = -1;
1286                 p->tex_Texture_FogHeightTexture = -1;
1287                 p->tex_Texture_FogMask = -1;
1288                 p->tex_Texture_Lightmap = -1;
1289                 p->tex_Texture_Deluxemap = -1;
1290                 p->tex_Texture_Attenuation = -1;
1291                 p->tex_Texture_Cube = -1;
1292                 p->tex_Texture_Refraction = -1;
1293                 p->tex_Texture_Reflection = -1;
1294                 p->tex_Texture_ShadowMap2D = -1;
1295                 p->tex_Texture_CubeProjection = -1;
1296                 p->tex_Texture_ScreenNormalMap = -1;
1297                 p->tex_Texture_ScreenDiffuse = -1;
1298                 p->tex_Texture_ScreenSpecular = -1;
1299                 p->tex_Texture_ReflectMask = -1;
1300                 p->tex_Texture_ReflectCube = -1;
1301                 p->tex_Texture_BounceGrid = -1;
1302                 // bind the texture samplers in use
1303                 sampler = 0;
1304                 if (p->loc_Texture_First           >= 0) {p->tex_Texture_First            = sampler;qglUniform1i(p->loc_Texture_First           , sampler);sampler++;}
1305                 if (p->loc_Texture_Second          >= 0) {p->tex_Texture_Second           = sampler;qglUniform1i(p->loc_Texture_Second          , sampler);sampler++;}
1306                 if (p->loc_Texture_GammaRamps      >= 0) {p->tex_Texture_GammaRamps       = sampler;qglUniform1i(p->loc_Texture_GammaRamps      , sampler);sampler++;}
1307                 if (p->loc_Texture_Normal          >= 0) {p->tex_Texture_Normal           = sampler;qglUniform1i(p->loc_Texture_Normal          , sampler);sampler++;}
1308                 if (p->loc_Texture_Color           >= 0) {p->tex_Texture_Color            = sampler;qglUniform1i(p->loc_Texture_Color           , sampler);sampler++;}
1309                 if (p->loc_Texture_Gloss           >= 0) {p->tex_Texture_Gloss            = sampler;qglUniform1i(p->loc_Texture_Gloss           , sampler);sampler++;}
1310                 if (p->loc_Texture_Glow            >= 0) {p->tex_Texture_Glow             = sampler;qglUniform1i(p->loc_Texture_Glow            , sampler);sampler++;}
1311                 if (p->loc_Texture_SecondaryNormal >= 0) {p->tex_Texture_SecondaryNormal  = sampler;qglUniform1i(p->loc_Texture_SecondaryNormal , sampler);sampler++;}
1312                 if (p->loc_Texture_SecondaryColor  >= 0) {p->tex_Texture_SecondaryColor   = sampler;qglUniform1i(p->loc_Texture_SecondaryColor  , sampler);sampler++;}
1313                 if (p->loc_Texture_SecondaryGloss  >= 0) {p->tex_Texture_SecondaryGloss   = sampler;qglUniform1i(p->loc_Texture_SecondaryGloss  , sampler);sampler++;}
1314                 if (p->loc_Texture_SecondaryGlow   >= 0) {p->tex_Texture_SecondaryGlow    = sampler;qglUniform1i(p->loc_Texture_SecondaryGlow   , sampler);sampler++;}
1315                 if (p->loc_Texture_Pants           >= 0) {p->tex_Texture_Pants            = sampler;qglUniform1i(p->loc_Texture_Pants           , sampler);sampler++;}
1316                 if (p->loc_Texture_Shirt           >= 0) {p->tex_Texture_Shirt            = sampler;qglUniform1i(p->loc_Texture_Shirt           , sampler);sampler++;}
1317                 if (p->loc_Texture_FogHeightTexture>= 0) {p->tex_Texture_FogHeightTexture = sampler;qglUniform1i(p->loc_Texture_FogHeightTexture, sampler);sampler++;}
1318                 if (p->loc_Texture_FogMask         >= 0) {p->tex_Texture_FogMask          = sampler;qglUniform1i(p->loc_Texture_FogMask         , sampler);sampler++;}
1319                 if (p->loc_Texture_Lightmap        >= 0) {p->tex_Texture_Lightmap         = sampler;qglUniform1i(p->loc_Texture_Lightmap        , sampler);sampler++;}
1320                 if (p->loc_Texture_Deluxemap       >= 0) {p->tex_Texture_Deluxemap        = sampler;qglUniform1i(p->loc_Texture_Deluxemap       , sampler);sampler++;}
1321                 if (p->loc_Texture_Attenuation     >= 0) {p->tex_Texture_Attenuation      = sampler;qglUniform1i(p->loc_Texture_Attenuation     , sampler);sampler++;}
1322                 if (p->loc_Texture_Cube            >= 0) {p->tex_Texture_Cube             = sampler;qglUniform1i(p->loc_Texture_Cube            , sampler);sampler++;}
1323                 if (p->loc_Texture_Refraction      >= 0) {p->tex_Texture_Refraction       = sampler;qglUniform1i(p->loc_Texture_Refraction      , sampler);sampler++;}
1324                 if (p->loc_Texture_Reflection      >= 0) {p->tex_Texture_Reflection       = sampler;qglUniform1i(p->loc_Texture_Reflection      , sampler);sampler++;}
1325                 if (p->loc_Texture_ShadowMap2D     >= 0) {p->tex_Texture_ShadowMap2D      = sampler;qglUniform1i(p->loc_Texture_ShadowMap2D     , sampler);sampler++;}
1326                 if (p->loc_Texture_CubeProjection  >= 0) {p->tex_Texture_CubeProjection   = sampler;qglUniform1i(p->loc_Texture_CubeProjection  , sampler);sampler++;}
1327                 if (p->loc_Texture_ScreenNormalMap >= 0) {p->tex_Texture_ScreenNormalMap  = sampler;qglUniform1i(p->loc_Texture_ScreenNormalMap , sampler);sampler++;}
1328                 if (p->loc_Texture_ScreenDiffuse   >= 0) {p->tex_Texture_ScreenDiffuse    = sampler;qglUniform1i(p->loc_Texture_ScreenDiffuse   , sampler);sampler++;}
1329                 if (p->loc_Texture_ScreenSpecular  >= 0) {p->tex_Texture_ScreenSpecular   = sampler;qglUniform1i(p->loc_Texture_ScreenSpecular  , sampler);sampler++;}
1330                 if (p->loc_Texture_ReflectMask     >= 0) {p->tex_Texture_ReflectMask      = sampler;qglUniform1i(p->loc_Texture_ReflectMask     , sampler);sampler++;}
1331                 if (p->loc_Texture_ReflectCube     >= 0) {p->tex_Texture_ReflectCube      = sampler;qglUniform1i(p->loc_Texture_ReflectCube     , sampler);sampler++;}
1332                 if (p->loc_Texture_BounceGrid      >= 0) {p->tex_Texture_BounceGrid       = sampler;qglUniform1i(p->loc_Texture_BounceGrid      , sampler);sampler++;}
1333                 // get the uniform block indices so we can bind them
1334 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1335                 if (vid.support.arb_uniform_buffer_object)
1336                         p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
1337                 else
1338 #endif
1339                         p->ubiloc_Skeletal_Transform12_UniformBlock = -1;
1340                 // clear the uniform block bindings
1341                 p->ubibind_Skeletal_Transform12_UniformBlock = -1;
1342                 // bind the uniform blocks in use
1343                 ubibind = 0;
1344 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1345                 if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;}
1346 #endif
1347                 // we're done compiling and setting up the shader, at least until it is used
1348                 CHECKGLERROR
1349                 Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler);
1350         }
1351         else
1352                 Con_Printf("^1GLSL shader %s failed!  some features may not work properly.\n", permutationname);
1353
1354         // free the strings
1355         if (sourcestring)
1356                 Mem_Free(sourcestring);
1357 }
1358
1359 static void R_SetupShader_SetPermutationGLSL(unsigned int mode, dpuint64 permutation)
1360 {
1361         r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation);
1362         if (r_glsl_permutation != perm)
1363         {
1364                 r_glsl_permutation = perm;
1365                 if (!r_glsl_permutation->program)
1366                 {
1367                         if (!r_glsl_permutation->compiled)
1368                         {
1369                                 Con_DPrintf("Compiling shader mode %u permutation %u\n", mode, permutation);
1370                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1371                         }
1372                         if (!r_glsl_permutation->program)
1373                         {
1374                                 // remove features until we find a valid permutation
1375                                 int i;
1376                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1377                                 {
1378                                         // reduce i more quickly whenever it would not remove any bits
1379                                         dpuint64 j = 1ll<<(SHADERPERMUTATION_COUNT-1-i);
1380                                         if (!(permutation & j))
1381                                                 continue;
1382                                         permutation -= j;
1383                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1384                                         if (!r_glsl_permutation->compiled)
1385                                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1386                                         if (r_glsl_permutation->program)
1387                                                 break;
1388                                 }
1389                                 if (i >= SHADERPERMUTATION_COUNT)
1390                                 {
1391                                         //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext);
1392                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1393                                         qglUseProgram(0);CHECKGLERROR
1394                                         return; // no bit left to clear, entire mode is broken
1395                                 }
1396                         }
1397                 }
1398                 CHECKGLERROR
1399                 qglUseProgram(r_glsl_permutation->program);CHECKGLERROR
1400         }
1401         if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
1402         if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
1403         if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time);
1404         CHECKGLERROR
1405 }
1406
1407 void R_GLSL_Restart_f(void)
1408 {
1409         unsigned int i, limit;
1410         switch(vid.renderpath)
1411         {
1412         case RENDERPATH_GL20:
1413         case RENDERPATH_GLES2:
1414                 {
1415                         r_glsl_permutation_t *p;
1416                         r_glsl_permutation = NULL;
1417                         limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
1418                         for (i = 0;i < limit;i++)
1419                         {
1420                                 if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
1421                                 {
1422                                         GL_Backend_FreeProgram(p->program);
1423                                         Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
1424                                 }
1425                         }
1426                         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
1427                 }
1428                 break;
1429         }
1430 }
1431
1432 static void R_GLSL_DumpShader_f(void)
1433 {
1434         int i, language, mode, dupe;
1435         char *text;
1436         shadermodeinfo_t *modeinfo;
1437         qfile_t *file;
1438
1439         for (language = 0;language < SHADERLANGUAGE_COUNT;language++)
1440         {
1441                 modeinfo = shadermodeinfo[language];
1442                 for (mode = 0;mode < SHADERMODE_COUNT;mode++)
1443                 {
1444                         // don't dump the same file multiple times (most or all shaders come from the same file)
1445                         for (dupe = mode - 1;dupe >= 0;dupe--)
1446                                 if (!strcmp(modeinfo[mode].filename, modeinfo[dupe].filename))
1447                                         break;
1448                         if (dupe >= 0)
1449                                 continue;
1450                         text = modeinfo[mode].builtinstring;
1451                         if (!text)
1452                                 continue;
1453                         file = FS_OpenRealFile(modeinfo[mode].filename, "w", false);
1454                         if (file)
1455                         {
1456                                 FS_Print(file, "/* The engine may define the following macros:\n");
1457                                 FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
1458                                 for (i = 0;i < SHADERMODE_COUNT;i++)
1459                                         FS_Print(file, modeinfo[i].pretext);
1460                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1461                                         FS_Print(file, shaderpermutationinfo[i].pretext);
1462                                 FS_Print(file, "*/\n");
1463                                 FS_Print(file, text);
1464                                 FS_Close(file);
1465                                 Con_Printf("%s written\n", modeinfo[mode].filename);
1466                         }
1467                         else
1468                                 Con_Printf("failed to write to %s\n", modeinfo[mode].filename);
1469                 }
1470         }
1471 }
1472
1473 void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemode, int rgbscale, qboolean usegamma, qboolean notrippy, qboolean suppresstexalpha)
1474 {
1475         dpuint64 permutation = 0;
1476         if (r_trippy.integer && !notrippy)
1477                 permutation |= SHADERPERMUTATION_TRIPPY;
1478         permutation |= SHADERPERMUTATION_VIEWTINT;
1479         if (first)
1480                 permutation |= SHADERPERMUTATION_DIFFUSE;
1481         if (second)
1482                 permutation |= SHADERPERMUTATION_SPECULAR;
1483         if (texturemode == GL_MODULATE)
1484                 permutation |= SHADERPERMUTATION_COLORMAPPING;
1485         else if (texturemode == GL_ADD)
1486                 permutation |= SHADERPERMUTATION_GLOW;
1487         else if (texturemode == GL_DECAL)
1488                 permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1489         if (usegamma && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
1490                 permutation |= SHADERPERMUTATION_GAMMARAMPS;
1491         if (suppresstexalpha)
1492                 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1493         if (!second)
1494                 texturemode = GL_MODULATE;
1495         if (vid.allowalphatocoverage)
1496                 GL_AlphaToCoverage(false);
1497         switch (vid.renderpath)
1498         {
1499         case RENDERPATH_GL20:
1500         case RENDERPATH_GLES2:
1501                 R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation);
1502                 if (r_glsl_permutation->tex_Texture_First >= 0)
1503                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , first );
1504                 if (r_glsl_permutation->tex_Texture_Second >= 0)
1505                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second, second);
1506                 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0)
1507                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps);
1508                 break;
1509         }
1510 }
1511
1512 void R_SetupShader_Generic_NoTexture(qboolean usegamma, qboolean notrippy)
1513 {
1514         R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, usegamma, notrippy, false);
1515 }
1516
1517 void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb, qboolean skeletal)
1518 {
1519         dpuint64 permutation = 0;
1520         if (r_trippy.integer && !notrippy)
1521                 permutation |= SHADERPERMUTATION_TRIPPY;
1522         if (depthrgb)
1523                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1524         if (skeletal)
1525                 permutation |= SHADERPERMUTATION_SKELETAL;
1526
1527         if (vid.allowalphatocoverage)
1528                 GL_AlphaToCoverage(false);
1529         switch (vid.renderpath)
1530         {
1531         case RENDERPATH_GL20:
1532         case RENDERPATH_GLES2:
1533                 R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
1534 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1535                 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);
1536 #endif
1537                 break;
1538         }
1539 }
1540
1541 #define BLENDFUNC_ALLOWS_COLORMOD      1
1542 #define BLENDFUNC_ALLOWS_FOG           2
1543 #define BLENDFUNC_ALLOWS_FOG_HACK0     4
1544 #define BLENDFUNC_ALLOWS_FOG_HACKALPHA 8
1545 #define BLENDFUNC_ALLOWS_ANYFOG        (BLENDFUNC_ALLOWS_FOG | BLENDFUNC_ALLOWS_FOG_HACK0 | BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1546 static int R_BlendFuncFlags(int src, int dst)
1547 {
1548         int r = 0;
1549
1550         // a blendfunc allows colormod if:
1551         // a) it can never keep the destination pixel invariant, or
1552         // b) it can keep the destination pixel invariant, and still can do so if colormodded
1553         // this is to prevent unintended side effects from colormod
1554
1555         // a blendfunc allows fog if:
1556         // blend(fog(src), fog(dst)) == fog(blend(src, dst))
1557         // this is to prevent unintended side effects from fog
1558
1559         // these checks are the output of fogeval.pl
1560
1561         r |= BLENDFUNC_ALLOWS_COLORMOD;
1562         if(src == GL_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1563         if(src == GL_DST_ALPHA && dst == GL_ONE_MINUS_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1564         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1565         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1566         if(src == GL_DST_COLOR && dst == GL_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1567         if(src == GL_DST_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1568         if(src == GL_DST_COLOR && dst == GL_ZERO) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1569         if(src == GL_ONE && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1570         if(src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG_HACKALPHA;
1571         if(src == GL_ONE && dst == GL_ZERO) r |= BLENDFUNC_ALLOWS_FOG;
1572         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1573         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1574         if(src == GL_ONE_MINUS_DST_COLOR && dst == GL_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1575         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1576         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1577         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1578         if(src == GL_ONE_MINUS_SRC_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1579         if(src == GL_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1580         if(src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1581         if(src == GL_ZERO && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG;
1582         if(src == GL_ZERO && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1583
1584         return r;
1585 }
1586
1587 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)
1588 {
1589         // select a permutation of the lighting shader appropriate to this
1590         // combination of texture, entity, light source, and fogging, only use the
1591         // minimum features necessary to avoid wasting rendering time in the
1592         // fragment shader on features that are not being used
1593         dpuint64 permutation = 0;
1594         unsigned int mode = 0;
1595         int blendfuncflags;
1596         texture_t *t = rsurface.texture;
1597         float m16f[16];
1598         matrix4x4_t tempmatrix;
1599         r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
1600         if (r_trippy.integer && !notrippy)
1601                 permutation |= SHADERPERMUTATION_TRIPPY;
1602         if (t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1603                 permutation |= SHADERPERMUTATION_ALPHAKILL;
1604         if (t->currentmaterialflags & MATERIALFLAG_OCCLUDE)
1605                 permutation |= SHADERPERMUTATION_OCCLUDE;
1606         if (t->r_water_waterscroll[0] && t->r_water_waterscroll[1])
1607                 permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
1608         if (rsurfacepass == RSURFPASS_BACKGROUND)
1609         {
1610                 // distorted background
1611                 if (t->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1612                 {
1613                         mode = SHADERMODE_WATER;
1614                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1615                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1616                         if((r_wateralpha.value < 1) && (t->currentmaterialflags & MATERIALFLAG_WATERALPHA))
1617                         {
1618                                 // this is the right thing to do for wateralpha
1619                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1620                                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1621                         }
1622                         else
1623                         {
1624                                 // this is the right thing to do for entity alpha
1625                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1626                                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1627                         }
1628                 }
1629                 else if (t->currentmaterialflags & MATERIALFLAG_REFRACTION)
1630                 {
1631                         mode = SHADERMODE_REFRACTION;
1632                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1633                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1634                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1635                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1636                 }
1637                 else
1638                 {
1639                         mode = SHADERMODE_GENERIC;
1640                         permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL;
1641                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1642                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1643                 }
1644                 if (vid.allowalphatocoverage)
1645                         GL_AlphaToCoverage(false);
1646         }
1647         else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
1648         {
1649                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1650                 {
1651                         switch(t->offsetmapping)
1652                         {
1653                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1654                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1655                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1656                         case OFFSETMAPPING_OFF: break;
1657                         }
1658                 }
1659                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1660                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1661                 // normalmap (deferred prepass), may use alpha test on diffuse
1662                 mode = SHADERMODE_DEFERREDGEOMETRY;
1663                 GL_BlendFunc(GL_ONE, GL_ZERO);
1664                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1665                 if (vid.allowalphatocoverage)
1666                         GL_AlphaToCoverage(false);
1667         }
1668         else if (rsurfacepass == RSURFPASS_RTLIGHT)
1669         {
1670                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1671                 {
1672                         switch(t->offsetmapping)
1673                         {
1674                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1675                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1676                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1677                         case OFFSETMAPPING_OFF: break;
1678                         }
1679                 }
1680                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1681                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1682                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1683                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1684                 // light source
1685                 mode = SHADERMODE_LIGHTSOURCE;
1686                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1687                         permutation |= SHADERPERMUTATION_CUBEFILTER;
1688                 if (VectorLength2(rtlightdiffuse) > 0)
1689                         permutation |= SHADERPERMUTATION_DIFFUSE;
1690                 if (VectorLength2(rtlightspecular) > 0)
1691                         permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1692                 if (r_refdef.fogenabled)
1693                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1694                 if (t->colormapping)
1695                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1696                 if (r_shadow_usingshadowmap2d)
1697                 {
1698                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1699                         if(r_shadow_shadowmapvsdct)
1700                                 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
1701
1702                         if (r_shadow_shadowmap2ddepthbuffer)
1703                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1704                 }
1705                 if (t->reflectmasktexture)
1706                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1707                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1708                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE);
1709                 if (vid.allowalphatocoverage)
1710                         GL_AlphaToCoverage(false);
1711         }
1712         else if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
1713         {
1714                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1715                 {
1716                         switch(t->offsetmapping)
1717                         {
1718                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1719                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1720                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1721                         case OFFSETMAPPING_OFF: break;
1722                         }
1723                 }
1724                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1725                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1726                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1727                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1728                 // directional model lighting
1729                 mode = SHADERMODE_LIGHTDIRECTION;
1730                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1731                         permutation |= SHADERPERMUTATION_GLOW;
1732                 if (VectorLength2(t->render_modellight_diffuse))
1733                         permutation |= SHADERPERMUTATION_DIFFUSE;
1734                 if (VectorLength2(t->render_modellight_specular) > 0)
1735                         permutation |= SHADERPERMUTATION_SPECULAR;
1736                 if (r_refdef.fogenabled)
1737                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1738                 if (t->colormapping)
1739                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1740                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1741                 {
1742                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1743                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1744
1745                         if (r_shadow_shadowmap2ddepthbuffer)
1746                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1747                 }
1748                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1749                         permutation |= SHADERPERMUTATION_REFLECTION;
1750                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1751                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1752                 if (t->reflectmasktexture)
1753                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1754                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld)
1755                 {
1756                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1757                         if (r_shadow_bouncegrid_state.directional)
1758                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1759                 }
1760                 GL_BlendFunc(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1761                 blendfuncflags = R_BlendFuncFlags(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1762                 // when using alphatocoverage, we don't need alphakill
1763                 if (vid.allowalphatocoverage)
1764                 {
1765                         if (r_transparent_alphatocoverage.integer)
1766                         {
1767                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1768                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1769                         }
1770                         else
1771                                 GL_AlphaToCoverage(false);
1772                 }
1773         }
1774         else
1775         {
1776                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1777                 {
1778                         switch(t->offsetmapping)
1779                         {
1780                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1781                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1782                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1783                         case OFFSETMAPPING_OFF: break;
1784                         }
1785                 }
1786                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1787                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1788                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1789                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1790                 // lightmapped wall
1791                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1792                         permutation |= SHADERPERMUTATION_GLOW;
1793                 if (r_refdef.fogenabled)
1794                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1795                 if (t->colormapping)
1796                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1797                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1798                 {
1799                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1800                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1801
1802                         if (r_shadow_shadowmap2ddepthbuffer)
1803                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1804                 }
1805                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1806                         permutation |= SHADERPERMUTATION_REFLECTION;
1807                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1808                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1809                 if (t->reflectmasktexture)
1810                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1811                 if (FAKELIGHT_ENABLED)
1812                 {
1813                         // fake lightmapping (q1bsp, q3bsp, fullbright map)
1814                         mode = SHADERMODE_FAKELIGHT;
1815                         permutation |= SHADERPERMUTATION_DIFFUSE;
1816                         if (VectorLength2(t->render_lightmap_specular) > 0)
1817                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1818                 }
1819                 else if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
1820                 {
1821                         // deluxemapping (light direction texture)
1822                         if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace)
1823                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1824                         else
1825                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1826                         permutation |= SHADERPERMUTATION_DIFFUSE;
1827                         if (VectorLength2(t->render_lightmap_specular) > 0)
1828                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1829                 }
1830                 else if (r_glsl_deluxemapping.integer >= 2)
1831                 {
1832                         // fake deluxemapping (uniform light direction in tangentspace)
1833                         if (rsurface.uselightmaptexture)
1834                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP;
1835                         else
1836                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR;
1837                         permutation |= SHADERPERMUTATION_DIFFUSE;
1838                         if (VectorLength2(t->render_lightmap_specular) > 0)
1839                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1840                 }
1841                 else if (rsurface.uselightmaptexture)
1842                 {
1843                         // ordinary lightmapping (q1bsp, q3bsp)
1844                         mode = SHADERMODE_LIGHTMAP;
1845                 }
1846                 else
1847                 {
1848                         // ordinary vertex coloring (q3bsp)
1849                         mode = SHADERMODE_VERTEXCOLOR;
1850                 }
1851                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld)
1852                 {
1853                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1854                         if (r_shadow_bouncegrid_state.directional)
1855                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1856                 }
1857                 GL_BlendFunc(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1858                 blendfuncflags = R_BlendFuncFlags(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1859                 // when using alphatocoverage, we don't need alphakill
1860                 if (vid.allowalphatocoverage)
1861                 {
1862                         if (r_transparent_alphatocoverage.integer)
1863                         {
1864                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1865                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1866                         }
1867                         else
1868                                 GL_AlphaToCoverage(false);
1869                 }
1870         }
1871         if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG))
1872                 permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE);
1873         if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1874                 permutation |= SHADERPERMUTATION_FOGALPHAHACK;
1875         switch(vid.renderpath)
1876         {
1877         case RENDERPATH_GL20:
1878         case RENDERPATH_GLES2:
1879                 if (!vid.useinterleavedarrays)
1880                 {
1881                         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);
1882                         R_Mesh_VertexPointer(     3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
1883                         R_Mesh_ColorPointer(      4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
1884                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
1885                         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
1886                         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
1887                         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
1888                         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
1889                         R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
1890                         R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
1891                         R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
1892                 }
1893                 else
1894                 {
1895                         RSurf_PrepareVerticesForBatch(BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | (rsurface.modellightmapcolor4f ? BATCHNEED_VERTEXMESH_VERTEXCOLOR : 0) | BATCHNEED_VERTEXMESH_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_VERTEXMESH_LIGHTMAP : 0) | (rsurface.entityskeletaltransform3x4 ? BATCHNEED_VERTEXMESH_SKELETAL : 0) | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
1896                         R_Mesh_PrepareVertices_Mesh(rsurface.batchnumvertices, rsurface.batchvertexmesh, rsurface.batchvertexmesh_vertexbuffer, rsurface.batchvertexmesh_bufferoffset);
1897                 }
1898                 // this has to be after RSurf_PrepareVerticesForBatch
1899                 if (rsurface.batchskeletaltransform3x4buffer)
1900                         permutation |= SHADERPERMUTATION_SKELETAL;
1901                 R_SetupShader_SetPermutationGLSL(mode, permutation);
1902 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1903                 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);
1904 #endif
1905                 if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
1906                 if (mode == SHADERMODE_LIGHTSOURCE)
1907                 {
1908                         if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
1909                         if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1910                         if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1911                         if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
1912                         if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
1913                         if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
1914         
1915                         // additive passes are only darkened by fog, not tinted
1916                         if (r_glsl_permutation->loc_FogColor >= 0)
1917                                 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1918                         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);
1919                 }
1920                 else
1921                 {
1922                         if (mode == SHADERMODE_FLATCOLOR)
1923                         {
1924                                 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]);
1925                         }
1926                         else if (mode == SHADERMODE_LIGHTDIRECTION)
1927                         {
1928                                 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]);
1929                                 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]);
1930                                 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]);
1931                                 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]);
1932                                 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]);
1933                                 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1934                                 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]);
1935                         }
1936                         else
1937                         {
1938                                 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]);
1939                                 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]);
1940                                 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]);
1941                                 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]);
1942                                 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]);
1943                         }
1944                         // additive passes are only darkened by fog, not tinted
1945                         if (r_glsl_permutation->loc_FogColor >= 0)
1946                         {
1947                                 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
1948                                         qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1949                                 else
1950                                         qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1951                         }
1952                         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);
1953                         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]);
1954                         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]);
1955                         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);
1956                         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);
1957                         if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, t->reflectmax - t->reflectmin);
1958                         if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, t->reflectmin);
1959                         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);
1960                         if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
1961                 }
1962                 if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
1963                 if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
1964                 if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
1965                 if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
1966                 {
1967                         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]);
1968                         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]);
1969                 }
1970                 else
1971                 {
1972                         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]);
1973                         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]);
1974                 }
1975
1976                 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]);
1977                 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));
1978                 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
1979                 if (r_glsl_permutation->loc_Color_Pants >= 0)
1980                 {
1981                         if (t->pantstexture)
1982                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
1983                         else
1984                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
1985                 }
1986                 if (r_glsl_permutation->loc_Color_Shirt >= 0)
1987                 {
1988                         if (t->shirttexture)
1989                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
1990                         else
1991                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
1992                 }
1993                 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]);
1994                 if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
1995                 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
1996                 if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
1997                 if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps,
1998                                 r_glsl_offsetmapping_scale.value*t->offsetscale,
1999                                 max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2000                                 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2001                                 max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
2002                         );
2003                 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);
2004                 if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, t->offsetbias);
2005                 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]);
2006                 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
2007                 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);}
2008                 if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
2009
2010                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First            , r_texture_white                                     );
2011                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second           , r_texture_white                                     );
2012                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps       , r_texture_gammaramps                                );
2013                 if (r_glsl_permutation->tex_Texture_Normal          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal           , t->nmaptexture                       );
2014                 if (r_glsl_permutation->tex_Texture_Color           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color            , t->basetexture                       );
2015                 if (r_glsl_permutation->tex_Texture_Gloss           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss            , t->glosstexture                      );
2016                 if (r_glsl_permutation->tex_Texture_Glow            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow             , t->glowtexture                       );
2017                 if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal  , t->backgroundnmaptexture             );
2018                 if (r_glsl_permutation->tex_Texture_SecondaryColor  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor   , t->backgroundbasetexture             );
2019                 if (r_glsl_permutation->tex_Texture_SecondaryGloss  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss   , t->backgroundglosstexture            );
2020                 if (r_glsl_permutation->tex_Texture_SecondaryGlow   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow    , t->backgroundglowtexture             );
2021                 if (r_glsl_permutation->tex_Texture_Pants           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants            , t->pantstexture                      );
2022                 if (r_glsl_permutation->tex_Texture_Shirt           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt            , t->shirttexture                      );
2023                 if (r_glsl_permutation->tex_Texture_ReflectMask     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask      , t->reflectmasktexture                );
2024                 if (r_glsl_permutation->tex_Texture_ReflectCube     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube      , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
2025                 if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture                          );
2026                 if (r_glsl_permutation->tex_Texture_FogMask         >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask          , r_texture_fogattenuation                            );
2027                 if (r_glsl_permutation->tex_Texture_Lightmap        >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap         , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
2028                 if (r_glsl_permutation->tex_Texture_Deluxemap       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Deluxemap        , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap);
2029                 if (r_glsl_permutation->tex_Texture_Attenuation     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation      , r_shadow_attenuationgradienttexture                 );
2030                 if (rsurfacepass == RSURFPASS_BACKGROUND)
2031                 {
2032                         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);
2033                         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);
2034                         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);
2035                 }
2036                 else
2037                 {
2038                         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);
2039                 }
2040                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap   , r_shadow_prepassgeometrynormalmaptexture            );
2041                 if (r_glsl_permutation->tex_Texture_ScreenDiffuse   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse     , r_shadow_prepasslightingdiffusetexture              );
2042                 if (r_glsl_permutation->tex_Texture_ScreenSpecular  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular    , r_shadow_prepasslightingspeculartexture             );
2043                 if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
2044                 {
2045                         if (r_glsl_permutation->tex_Texture_ShadowMap2D     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture                           );
2046                         if (rsurface.rtlight)
2047                         {
2048                                 if (r_glsl_permutation->tex_Texture_Cube            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube              , rsurface.rtlight->currentcubemap                    );
2049                                 if (r_glsl_permutation->tex_Texture_CubeProjection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection    , r_shadow_shadowmapvsdcttexture                      );
2050                         }
2051                 }
2052                 if (r_glsl_permutation->tex_Texture_BounceGrid  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
2053                 CHECKGLERROR
2054                 break;
2055         }
2056 }
2057
2058 void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
2059 {
2060         // select a permutation of the lighting shader appropriate to this
2061         // combination of texture, entity, light source, and fogging, only use the
2062         // minimum features necessary to avoid wasting rendering time in the
2063         // fragment shader on features that are not being used
2064         dpuint64 permutation = 0;
2065         unsigned int mode = 0;
2066         const float *lightcolorbase = rtlight->currentcolor;
2067         float ambientscale = rtlight->ambientscale;
2068         float diffusescale = rtlight->diffusescale;
2069         float specularscale = rtlight->specularscale;
2070         // this is the location of the light in view space
2071         vec3_t viewlightorigin;
2072         // this transforms from view space (camera) to light space (cubemap)
2073         matrix4x4_t viewtolight;
2074         matrix4x4_t lighttoview;
2075         float viewtolight16f[16];
2076         // light source
2077         mode = SHADERMODE_DEFERREDLIGHTSOURCE;
2078         if (rtlight->currentcubemap != r_texture_whitecube)
2079                 permutation |= SHADERPERMUTATION_CUBEFILTER;
2080         if (diffusescale > 0)
2081                 permutation |= SHADERPERMUTATION_DIFFUSE;
2082         if (specularscale > 0 && r_shadow_gloss.integer > 0)
2083                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2084         if (r_shadow_usingshadowmap2d)
2085         {
2086                 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
2087                 if (r_shadow_shadowmapvsdct)
2088                         permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
2089
2090                 if (r_shadow_shadowmap2ddepthbuffer)
2091                         permutation |= SHADERPERMUTATION_DEPTHRGB;
2092         }
2093         if (vid.allowalphatocoverage)
2094                 GL_AlphaToCoverage(false);
2095         Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
2096         Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
2097         Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
2098         Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
2099         switch(vid.renderpath)
2100         {
2101         case RENDERPATH_GL20:
2102         case RENDERPATH_GLES2:
2103                 R_SetupShader_SetPermutationGLSL(mode, permutation);
2104                 if (r_glsl_permutation->loc_LightPosition             >= 0) qglUniform3f(       r_glsl_permutation->loc_LightPosition            , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
2105                 if (r_glsl_permutation->loc_ViewToLight               >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight              , 1, false, viewtolight16f);
2106                 if (r_glsl_permutation->loc_DeferredColor_Ambient     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Ambient    , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
2107                 if (r_glsl_permutation->loc_DeferredColor_Diffuse     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
2108                 if (r_glsl_permutation->loc_DeferredColor_Specular    >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Specular   , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
2109                 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]);
2110                 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]);
2111                 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);
2112                 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]);
2113                 if (r_glsl_permutation->loc_PixelToScreenTexCoord     >= 0) qglUniform2f(       r_glsl_permutation->loc_PixelToScreenTexCoord    , 1.0f/vid.width, 1.0f/vid.height);
2114
2115                 if (r_glsl_permutation->tex_Texture_Attenuation       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation        , r_shadow_attenuationgradienttexture                 );
2116                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap    , r_shadow_prepassgeometrynormalmaptexture            );
2117                 if (r_glsl_permutation->tex_Texture_Cube              >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube               , rsurface.rtlight->currentcubemap                    );
2118                 if (r_glsl_permutation->tex_Texture_ShadowMap2D       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D        , r_shadow_shadowmap2ddepthtexture                    );
2119                 if (r_glsl_permutation->tex_Texture_CubeProjection    >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection     , r_shadow_shadowmapvsdcttexture                      );
2120                 break;
2121         }
2122 }
2123
2124 #define SKINFRAME_HASH 1024
2125
2126 typedef struct
2127 {
2128         unsigned int loadsequence; // incremented each level change
2129         memexpandablearray_t array;
2130         skinframe_t *hash[SKINFRAME_HASH];
2131 }
2132 r_skinframe_t;
2133 r_skinframe_t r_skinframe;
2134
2135 void R_SkinFrame_PrepareForPurge(void)
2136 {
2137         r_skinframe.loadsequence++;
2138         // wrap it without hitting zero
2139         if (r_skinframe.loadsequence >= 200)
2140                 r_skinframe.loadsequence = 1;
2141 }
2142
2143 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
2144 {
2145         if (!skinframe)
2146                 return;
2147         // mark the skinframe as used for the purging code
2148         skinframe->loadsequence = r_skinframe.loadsequence;
2149 }
2150
2151 void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
2152 {
2153         if (s == NULL)
2154                 return;
2155         if (s->merged == s->base)
2156                 s->merged = NULL;
2157         R_PurgeTexture(s->stain); s->stain = NULL;
2158         R_PurgeTexture(s->merged); s->merged = NULL;
2159         R_PurgeTexture(s->base); s->base = NULL;
2160         R_PurgeTexture(s->pants); s->pants = NULL;
2161         R_PurgeTexture(s->shirt); s->shirt = NULL;
2162         R_PurgeTexture(s->nmap); s->nmap = NULL;
2163         R_PurgeTexture(s->gloss); s->gloss = NULL;
2164         R_PurgeTexture(s->glow); s->glow = NULL;
2165         R_PurgeTexture(s->fog); s->fog = NULL;
2166         R_PurgeTexture(s->reflect); s->reflect = NULL;
2167         s->loadsequence = 0;
2168 }
2169
2170 void R_SkinFrame_Purge(void)
2171 {
2172         int i;
2173         skinframe_t *s;
2174         for (i = 0;i < SKINFRAME_HASH;i++)
2175         {
2176                 for (s = r_skinframe.hash[i];s;s = s->next)
2177                 {
2178                         if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
2179                                 R_SkinFrame_PurgeSkinFrame(s);
2180                 }
2181         }
2182 }
2183
2184 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
2185         skinframe_t *item;
2186         char basename[MAX_QPATH];
2187
2188         Image_StripImageExtension(name, basename, sizeof(basename));
2189
2190         if( last == NULL ) {
2191                 int hashindex;
2192                 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2193                 item = r_skinframe.hash[hashindex];
2194         } else {
2195                 item = last->next;
2196         }
2197
2198         // linearly search through the hash bucket
2199         for( ; item ; item = item->next ) {
2200                 if( !strcmp( item->basename, basename ) ) {
2201                         return item;
2202                 }
2203         }
2204         return NULL;
2205 }
2206
2207 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add)
2208 {
2209         skinframe_t *item;
2210         int hashindex;
2211         char basename[MAX_QPATH];
2212
2213         Image_StripImageExtension(name, basename, sizeof(basename));
2214
2215         hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2216         for (item = r_skinframe.hash[hashindex];item;item = item->next)
2217                 if (!strcmp(item->basename, basename) && (comparecrc < 0 || (item->textureflags == textureflags && item->comparewidth == comparewidth && item->compareheight == compareheight && item->comparecrc == comparecrc)))
2218                         break;
2219
2220         if (!item)
2221         {
2222                 if (!add)
2223                         return NULL;
2224                 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
2225                 memset(item, 0, sizeof(*item));
2226                 strlcpy(item->basename, basename, sizeof(item->basename));
2227                 item->textureflags = textureflags & ~TEXF_FORCE_RELOAD;
2228                 item->comparewidth = comparewidth;
2229                 item->compareheight = compareheight;
2230                 item->comparecrc = comparecrc;
2231                 item->next = r_skinframe.hash[hashindex];
2232                 r_skinframe.hash[hashindex] = item;
2233         }
2234         else if (textureflags & TEXF_FORCE_RELOAD)
2235         {
2236                 if (!add)
2237                         return NULL;
2238                 R_SkinFrame_PurgeSkinFrame(item);
2239         }
2240
2241         R_SkinFrame_MarkUsed(item);
2242         return item;
2243 }
2244
2245 #define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
2246         { \
2247                 unsigned long long avgcolor[5], wsum; \
2248                 int pix, comp, w; \
2249                 avgcolor[0] = 0; \
2250                 avgcolor[1] = 0; \
2251                 avgcolor[2] = 0; \
2252                 avgcolor[3] = 0; \
2253                 avgcolor[4] = 0; \
2254                 wsum = 0; \
2255                 for(pix = 0; pix < cnt; ++pix) \
2256                 { \
2257                         w = 0; \
2258                         for(comp = 0; comp < 3; ++comp) \
2259                                 w += getpixel; \
2260                         if(w) /* ignore perfectly black pixels because that is better for model skins */ \
2261                         { \
2262                                 ++wsum; \
2263                                 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2264                                 w = getpixel; \
2265                                 for(comp = 0; comp < 3; ++comp) \
2266                                         avgcolor[comp] += getpixel * w; \
2267                                 avgcolor[3] += w; \
2268                         } \
2269                         /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2270                         avgcolor[4] += getpixel; \
2271                 } \
2272                 if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
2273                         avgcolor[3] = 1; \
2274                 skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
2275                 skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
2276                 skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
2277                 skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
2278         }
2279
2280 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2281 {
2282         skinframe_t *skinframe;
2283
2284         if (cls.state == ca_dedicated)
2285                 return NULL;
2286
2287         // return an existing skinframe if already loaded
2288         // if loading of the first image fails, don't make a new skinframe as it
2289         // would cause all future lookups of this to be missing
2290         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, -1, false);
2291         if (skinframe && skinframe->base)
2292                 return skinframe;
2293
2294         return R_SkinFrame_LoadExternal_SkinFrame(skinframe, name, textureflags, complain, fallbacknotexture);
2295 }
2296
2297 extern cvar_t gl_picmip;
2298 skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2299 {
2300         int j;
2301         unsigned char *pixels;
2302         unsigned char *bumppixels;
2303         unsigned char *basepixels = NULL;
2304         int basepixels_width = 0;
2305         int basepixels_height = 0;
2306         rtexture_t *ddsbase = NULL;
2307         qboolean ddshasalpha = false;
2308         float ddsavgcolor[4];
2309         char basename[MAX_QPATH];
2310         int miplevel = R_PicmipForFlags(textureflags);
2311         int savemiplevel = miplevel;
2312         int mymiplevel;
2313         char vabuf[1024];
2314
2315         if (cls.state == ca_dedicated)
2316                 return NULL;
2317
2318         Image_StripImageExtension(name, basename, sizeof(basename));
2319
2320         // check for DDS texture file first
2321         if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2322         {
2323                 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2324                 if (basepixels == NULL && fallbacknotexture)
2325                         basepixels = Image_GenerateNoTexture();
2326                 if (basepixels == NULL)
2327                         return NULL;
2328         }
2329
2330         // FIXME handle miplevel
2331
2332         if (developer_loading.integer)
2333                 Con_Printf("loading skin \"%s\"\n", name);
2334
2335         // we've got some pixels to store, so really allocate this new texture now
2336         if (!skinframe)
2337                 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2338         textureflags &= ~TEXF_FORCE_RELOAD;
2339         skinframe->stain = NULL;
2340         skinframe->merged = NULL;
2341         skinframe->base = NULL;
2342         skinframe->pants = NULL;
2343         skinframe->shirt = NULL;
2344         skinframe->nmap = NULL;
2345         skinframe->gloss = NULL;
2346         skinframe->glow = NULL;
2347         skinframe->fog = NULL;
2348         skinframe->reflect = NULL;
2349         skinframe->hasalpha = false;
2350         // we could store the q2animname here too
2351
2352         if (ddsbase)
2353         {
2354                 skinframe->base = ddsbase;
2355                 skinframe->hasalpha = ddshasalpha;
2356                 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2357                 if (r_loadfog && skinframe->hasalpha)
2358                         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);
2359                 //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]);
2360         }
2361         else
2362         {
2363                 basepixels_width = image_width;
2364                 basepixels_height = image_height;
2365                 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);
2366                 if (textureflags & TEXF_ALPHA)
2367                 {
2368                         for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2369                         {
2370                                 if (basepixels[j] < 255)
2371                                 {
2372                                         skinframe->hasalpha = true;
2373                                         break;
2374                                 }
2375                         }
2376                         if (r_loadfog && skinframe->hasalpha)
2377                         {
2378                                 // has transparent pixels
2379                                 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2380                                 for (j = 0;j < image_width * image_height * 4;j += 4)
2381                                 {
2382                                         pixels[j+0] = 255;
2383                                         pixels[j+1] = 255;
2384                                         pixels[j+2] = 255;
2385                                         pixels[j+3] = basepixels[j+3];
2386                                 }
2387                                 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);
2388                                 Mem_Free(pixels);
2389                         }
2390                 }
2391                 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2392 #ifndef USE_GLES2
2393                 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2394                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->base)
2395                         R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2396                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->fog)
2397                         R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2398 #endif
2399         }
2400
2401         if (r_loaddds)
2402         {
2403                 mymiplevel = savemiplevel;
2404                 if (r_loadnormalmap)
2405                         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);
2406                 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2407                 if (r_loadgloss)
2408                         skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2409                 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2410                 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2411                 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2412         }
2413
2414         // _norm is the name used by tenebrae and has been adopted as standard
2415         if (r_loadnormalmap && skinframe->nmap == NULL)
2416         {
2417                 mymiplevel = savemiplevel;
2418                 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2419                 {
2420                         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);
2421                         Mem_Free(pixels);
2422                         pixels = NULL;
2423                 }
2424                 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2425                 {
2426                         pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2427                         Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2428                         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);
2429                         Mem_Free(pixels);
2430                         Mem_Free(bumppixels);
2431                 }
2432                 else if (r_shadow_bumpscale_basetexture.value > 0)
2433                 {
2434                         pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2435                         Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2436                         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);
2437                         Mem_Free(pixels);
2438                 }
2439 #ifndef USE_GLES2
2440                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->nmap)
2441                         R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2442 #endif
2443         }
2444
2445         // _luma is supported only for tenebrae compatibility
2446         // _glow is the preferred name
2447         mymiplevel = savemiplevel;
2448         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_luma", skinframe->basename), false, false, false, &mymiplevel))))
2449         {
2450                 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);
2451 #ifndef USE_GLES2
2452                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->glow)
2453                         R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2454 #endif
2455                 Mem_Free(pixels);pixels = NULL;
2456         }
2457
2458         mymiplevel = savemiplevel;
2459         if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2460         {
2461                 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);
2462 #ifndef USE_GLES2
2463                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->gloss)
2464                         R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2465 #endif
2466                 Mem_Free(pixels);
2467                 pixels = NULL;
2468         }
2469
2470         mymiplevel = savemiplevel;
2471         if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2472         {
2473                 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);
2474 #ifndef USE_GLES2
2475                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->pants)
2476                         R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2477 #endif
2478                 Mem_Free(pixels);
2479                 pixels = NULL;
2480         }
2481
2482         mymiplevel = savemiplevel;
2483         if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2484         {
2485                 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);
2486 #ifndef USE_GLES2
2487                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->shirt)
2488                         R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2489 #endif
2490                 Mem_Free(pixels);
2491                 pixels = NULL;
2492         }
2493
2494         mymiplevel = savemiplevel;
2495         if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2496         {
2497                 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);
2498 #ifndef USE_GLES2
2499                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->reflect)
2500                         R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2501 #endif
2502                 Mem_Free(pixels);
2503                 pixels = NULL;
2504         }
2505
2506         if (basepixels)
2507                 Mem_Free(basepixels);
2508
2509         return skinframe;
2510 }
2511
2512 // this is only used by .spr32 sprites, HL .spr files, HL .bsp files
2513 skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, qboolean sRGB)
2514 {
2515         int i;
2516         skinframe_t *skinframe;
2517         char vabuf[1024];
2518
2519         if (cls.state == ca_dedicated)
2520                 return NULL;
2521
2522         // if already loaded just return it, otherwise make a new skinframe
2523         skinframe = R_SkinFrame_Find(name, textureflags, width, height, (!(textureflags & TEXF_FORCE_RELOAD) && skindata) ? CRC_Block(skindata, width*height*4) : -1, true);
2524         if (skinframe->base)
2525                 return skinframe;
2526         textureflags &= ~TEXF_FORCE_RELOAD;
2527
2528         skinframe->stain = NULL;
2529         skinframe->merged = NULL;
2530         skinframe->base = NULL;
2531         skinframe->pants = NULL;
2532         skinframe->shirt = NULL;
2533         skinframe->nmap = NULL;
2534         skinframe->gloss = NULL;
2535         skinframe->glow = NULL;
2536         skinframe->fog = NULL;
2537         skinframe->reflect = NULL;
2538         skinframe->hasalpha = false;
2539
2540         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2541         if (!skindata)
2542                 return NULL;
2543
2544         if (developer_loading.integer)
2545                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2546
2547         if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2548         {
2549                 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2550                 unsigned char *b = a + width * height * 4;
2551                 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2552                 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);
2553                 Mem_Free(a);
2554         }
2555         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2556         if (textureflags & TEXF_ALPHA)
2557         {
2558                 for (i = 3;i < width * height * 4;i += 4)
2559                 {
2560                         if (skindata[i] < 255)
2561                         {
2562                                 skinframe->hasalpha = true;
2563                                 break;
2564                         }
2565                 }
2566                 if (r_loadfog && skinframe->hasalpha)
2567                 {
2568                         unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2569                         memcpy(fogpixels, skindata, width * height * 4);
2570                         for (i = 0;i < width * height * 4;i += 4)
2571                                 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2572                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2573                         Mem_Free(fogpixels);
2574                 }
2575         }
2576
2577         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2578         //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]);
2579
2580         return skinframe;
2581 }
2582
2583 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2584 {
2585         int i;
2586         int featuresmask;
2587         skinframe_t *skinframe;
2588
2589         if (cls.state == ca_dedicated)
2590                 return NULL;
2591
2592         // if already loaded just return it, otherwise make a new skinframe
2593         skinframe = R_SkinFrame_Find(name, textureflags, width, height, (!(textureflags & TEXF_FORCE_RELOAD) && skindata) ? CRC_Block(skindata, width*height) : -1, true);
2594         if (skinframe->base)
2595                 return skinframe;
2596         //textureflags &= ~TEXF_FORCE_RELOAD;
2597
2598         skinframe->stain = NULL;
2599         skinframe->merged = NULL;
2600         skinframe->base = NULL;
2601         skinframe->pants = NULL;
2602         skinframe->shirt = NULL;
2603         skinframe->nmap = NULL;
2604         skinframe->gloss = NULL;
2605         skinframe->glow = NULL;
2606         skinframe->fog = NULL;
2607         skinframe->reflect = NULL;
2608         skinframe->hasalpha = false;
2609
2610         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2611         if (!skindata)
2612                 return NULL;
2613
2614         if (developer_loading.integer)
2615                 Con_Printf("loading quake skin \"%s\"\n", name);
2616
2617         // 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)
2618         skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2619         memcpy(skinframe->qpixels, skindata, width*height);
2620         skinframe->qwidth = width;
2621         skinframe->qheight = height;
2622
2623         featuresmask = 0;
2624         for (i = 0;i < width * height;i++)
2625                 featuresmask |= palette_featureflags[skindata[i]];
2626
2627         skinframe->hasalpha = false;
2628         // fence textures
2629         if (name[0] == '{')
2630                 skinframe->hasalpha = true;
2631         skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2632         skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2633         skinframe->qgeneratemerged = true;
2634         skinframe->qgeneratebase = skinframe->qhascolormapping;
2635         skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2636
2637         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2638         //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]);
2639
2640         return skinframe;
2641 }
2642
2643 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboolean colormapped)
2644 {
2645         int width;
2646         int height;
2647         unsigned char *skindata;
2648         char vabuf[1024];
2649
2650         if (!skinframe->qpixels)
2651                 return;
2652
2653         if (!skinframe->qhascolormapping)
2654                 colormapped = false;
2655
2656         if (colormapped)
2657         {
2658                 if (!skinframe->qgeneratebase)
2659                         return;
2660         }
2661         else
2662         {
2663                 if (!skinframe->qgeneratemerged)
2664                         return;
2665         }
2666
2667         width = skinframe->qwidth;
2668         height = skinframe->qheight;
2669         skindata = skinframe->qpixels;
2670
2671         if (skinframe->qgeneratenmap)
2672         {
2673                 unsigned char *a, *b;
2674                 skinframe->qgeneratenmap = false;
2675                 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2676                 b = a + width * height * 4;
2677                 // use either a custom palette or the quake palette
2678                 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2679                 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2680                 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);
2681                 Mem_Free(a);
2682         }
2683
2684         if (skinframe->qgenerateglow)
2685         {
2686                 skinframe->qgenerateglow = false;
2687                 if (skinframe->hasalpha) // fence textures
2688                         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
2689                 else
2690                         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
2691         }
2692
2693         if (colormapped)
2694         {
2695                 skinframe->qgeneratebase = false;
2696                 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);
2697                 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);
2698                 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);
2699         }
2700         else
2701         {
2702                 skinframe->qgeneratemerged = false;
2703                 if (skinframe->hasalpha) // fence textures
2704                         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);
2705                 else
2706                         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);
2707         }
2708
2709         if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2710         {
2711                 Mem_Free(skinframe->qpixels);
2712                 skinframe->qpixels = NULL;
2713         }
2714 }
2715
2716 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)
2717 {
2718         int i;
2719         skinframe_t *skinframe;
2720         char vabuf[1024];
2721
2722         if (cls.state == ca_dedicated)
2723                 return NULL;
2724
2725         // if already loaded just return it, otherwise make a new skinframe
2726         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2727         if (skinframe->base)
2728                 return skinframe;
2729         textureflags &= ~TEXF_FORCE_RELOAD;
2730
2731         skinframe->stain = NULL;
2732         skinframe->merged = NULL;
2733         skinframe->base = NULL;
2734         skinframe->pants = NULL;
2735         skinframe->shirt = NULL;
2736         skinframe->nmap = NULL;
2737         skinframe->gloss = NULL;
2738         skinframe->glow = NULL;
2739         skinframe->fog = NULL;
2740         skinframe->reflect = NULL;
2741         skinframe->hasalpha = false;
2742
2743         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2744         if (!skindata)
2745                 return NULL;
2746
2747         if (developer_loading.integer)
2748                 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2749
2750         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2751         if ((textureflags & TEXF_ALPHA) && alphapalette)
2752         {
2753                 for (i = 0;i < width * height;i++)
2754                 {
2755                         if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2756                         {
2757                                 skinframe->hasalpha = true;
2758                                 break;
2759                         }
2760                 }
2761                 if (r_loadfog && skinframe->hasalpha)
2762                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2763         }
2764
2765         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2766         //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]);
2767
2768         return skinframe;
2769 }
2770
2771 skinframe_t *R_SkinFrame_LoadMissing(void)
2772 {
2773         skinframe_t *skinframe;
2774
2775         if (cls.state == ca_dedicated)
2776                 return NULL;
2777
2778         skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2779         skinframe->stain = NULL;
2780         skinframe->merged = NULL;
2781         skinframe->base = NULL;
2782         skinframe->pants = NULL;
2783         skinframe->shirt = NULL;
2784         skinframe->nmap = NULL;
2785         skinframe->gloss = NULL;
2786         skinframe->glow = NULL;
2787         skinframe->fog = NULL;
2788         skinframe->reflect = NULL;
2789         skinframe->hasalpha = false;
2790
2791         skinframe->avgcolor[0] = rand() / RAND_MAX;
2792         skinframe->avgcolor[1] = rand() / RAND_MAX;
2793         skinframe->avgcolor[2] = rand() / RAND_MAX;
2794         skinframe->avgcolor[3] = 1;
2795
2796         return skinframe;
2797 }
2798
2799 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2800 {
2801         int x, y;
2802         static unsigned char pix[16][16][4];
2803
2804         if (cls.state == ca_dedicated)
2805                 return NULL;
2806
2807         // this makes a light grey/dark grey checkerboard texture
2808         if (!pix[0][0][3])
2809         {
2810                 for (y = 0; y < 16; y++)
2811                 {
2812                         for (x = 0; x < 16; x++)
2813                         {
2814                                 if ((y < 8) ^ (x < 8))
2815                                 {
2816                                         pix[y][x][0] = 128;
2817                                         pix[y][x][1] = 128;
2818                                         pix[y][x][2] = 128;
2819                                         pix[y][x][3] = 255;
2820                                 }
2821                                 else
2822                                 {
2823                                         pix[y][x][0] = 64;
2824                                         pix[y][x][1] = 64;
2825                                         pix[y][x][2] = 64;
2826                                         pix[y][x][3] = 255;
2827                                 }
2828                         }
2829                 }
2830         }
2831
2832         return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, pix[0][0], 16, 16, false);
2833 }
2834
2835 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qboolean sRGB)
2836 {
2837         skinframe_t *skinframe;
2838         if (cls.state == ca_dedicated)
2839                 return NULL;
2840         // if already loaded just return it, otherwise make a new skinframe
2841         skinframe = R_SkinFrame_Find(name, textureflags, width, height, (textureflags & TEXF_FORCE_RELOAD) ? -1 : 0, true);
2842         if (skinframe->base)
2843                 return skinframe;
2844         textureflags &= ~TEXF_FORCE_RELOAD;
2845         skinframe->stain = NULL;
2846         skinframe->merged = NULL;
2847         skinframe->base = NULL;
2848         skinframe->pants = NULL;
2849         skinframe->shirt = NULL;
2850         skinframe->nmap = NULL;
2851         skinframe->gloss = NULL;
2852         skinframe->glow = NULL;
2853         skinframe->fog = NULL;
2854         skinframe->reflect = NULL;
2855         skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2856         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2857         if (!tex)
2858                 return NULL;
2859         if (developer_loading.integer)
2860                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2861         skinframe->base = skinframe->merged = tex;
2862         Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2863         return skinframe;
2864 }
2865
2866 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2867 typedef struct suffixinfo_s
2868 {
2869         const char *suffix;
2870         qboolean flipx, flipy, flipdiagonal;
2871 }
2872 suffixinfo_t;
2873 static suffixinfo_t suffix[3][6] =
2874 {
2875         {
2876                 {"px",   false, false, false},
2877                 {"nx",   false, false, false},
2878                 {"py",   false, false, false},
2879                 {"ny",   false, false, false},
2880                 {"pz",   false, false, false},
2881                 {"nz",   false, false, false}
2882         },
2883         {
2884                 {"posx", false, false, false},
2885                 {"negx", false, false, false},
2886                 {"posy", false, false, false},
2887                 {"negy", false, false, false},
2888                 {"posz", false, false, false},
2889                 {"negz", false, false, false}
2890         },
2891         {
2892                 {"rt",    true, false,  true},
2893                 {"lf",   false,  true,  true},
2894                 {"ft",    true,  true, false},
2895                 {"bk",   false, false, false},
2896                 {"up",    true, false,  true},
2897                 {"dn",    true, false,  true}
2898         }
2899 };
2900
2901 static int componentorder[4] = {0, 1, 2, 3};
2902
2903 static rtexture_t *R_LoadCubemap(const char *basename)
2904 {
2905         int i, j, cubemapsize;
2906         unsigned char *cubemappixels, *image_buffer;
2907         rtexture_t *cubemaptexture;
2908         char name[256];
2909         // must start 0 so the first loadimagepixels has no requested width/height
2910         cubemapsize = 0;
2911         cubemappixels = NULL;
2912         cubemaptexture = NULL;
2913         // keep trying different suffix groups (posx, px, rt) until one loads
2914         for (j = 0;j < 3 && !cubemappixels;j++)
2915         {
2916                 // load the 6 images in the suffix group
2917                 for (i = 0;i < 6;i++)
2918                 {
2919                         // generate an image name based on the base and and suffix
2920                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2921                         // load it
2922                         if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
2923                         {
2924                                 // an image loaded, make sure width and height are equal
2925                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
2926                                 {
2927                                         // if this is the first image to load successfully, allocate the cubemap memory
2928                                         if (!cubemappixels && image_width >= 1)
2929                                         {
2930                                                 cubemapsize = image_width;
2931                                                 // note this clears to black, so unavailable sides are black
2932                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2933                                         }
2934                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2935                                         if (cubemappixels)
2936                                                 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);
2937                                 }
2938                                 else
2939                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2940                                 // free the image
2941                                 Mem_Free(image_buffer);
2942                         }
2943                 }
2944         }
2945         // if a cubemap loaded, upload it
2946         if (cubemappixels)
2947         {
2948                 if (developer_loading.integer)
2949                         Con_Printf("loading cubemap \"%s\"\n", basename);
2950
2951                 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) | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
2952                 Mem_Free(cubemappixels);
2953         }
2954         else
2955         {
2956                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
2957                 if (developer_loading.integer)
2958                 {
2959                         Con_Printf("(tried tried images ");
2960                         for (j = 0;j < 3;j++)
2961                                 for (i = 0;i < 6;i++)
2962                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2963                         Con_Print(" and was unable to find any of them).\n");
2964                 }
2965         }
2966         return cubemaptexture;
2967 }
2968
2969 rtexture_t *R_GetCubemap(const char *basename)
2970 {
2971         int i;
2972         for (i = 0;i < r_texture_numcubemaps;i++)
2973                 if (r_texture_cubemaps[i] != NULL)
2974                         if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
2975                                 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
2976         if (i >= MAX_CUBEMAPS || !r_main_mempool)
2977                 return r_texture_whitecube;
2978         r_texture_numcubemaps++;
2979         r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
2980         strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
2981         r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
2982         return r_texture_cubemaps[i]->texture;
2983 }
2984
2985 static void R_Main_FreeViewCache(void)
2986 {
2987         if (r_refdef.viewcache.entityvisible)
2988                 Mem_Free(r_refdef.viewcache.entityvisible);
2989         if (r_refdef.viewcache.world_pvsbits)
2990                 Mem_Free(r_refdef.viewcache.world_pvsbits);
2991         if (r_refdef.viewcache.world_leafvisible)
2992                 Mem_Free(r_refdef.viewcache.world_leafvisible);
2993         if (r_refdef.viewcache.world_surfacevisible)
2994                 Mem_Free(r_refdef.viewcache.world_surfacevisible);
2995         memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
2996 }
2997
2998 static void R_Main_ResizeViewCache(void)
2999 {
3000         int numentities = r_refdef.scene.numentities;
3001         int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
3002         int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
3003         int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
3004         int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
3005         if (r_refdef.viewcache.maxentities < numentities)
3006         {
3007                 r_refdef.viewcache.maxentities = numentities;
3008                 if (r_refdef.viewcache.entityvisible)
3009                         Mem_Free(r_refdef.viewcache.entityvisible);
3010                 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
3011         }
3012         if (r_refdef.viewcache.world_numclusters != numclusters)
3013         {
3014                 r_refdef.viewcache.world_numclusters = numclusters;
3015                 r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
3016                 if (r_refdef.viewcache.world_pvsbits)
3017                         Mem_Free(r_refdef.viewcache.world_pvsbits);
3018                 r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
3019         }
3020         if (r_refdef.viewcache.world_numleafs != numleafs)
3021         {
3022                 r_refdef.viewcache.world_numleafs = numleafs;
3023                 if (r_refdef.viewcache.world_leafvisible)
3024                         Mem_Free(r_refdef.viewcache.world_leafvisible);
3025                 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
3026         }
3027         if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
3028         {
3029                 r_refdef.viewcache.world_numsurfaces = numsurfaces;
3030                 if (r_refdef.viewcache.world_surfacevisible)
3031                         Mem_Free(r_refdef.viewcache.world_surfacevisible);
3032                 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
3033         }
3034 }
3035
3036 extern rtexture_t *loadingscreentexture;
3037 static void gl_main_start(void)
3038 {
3039         loadingscreentexture = NULL;
3040         r_texture_blanknormalmap = NULL;
3041         r_texture_white = NULL;
3042         r_texture_grey128 = NULL;
3043         r_texture_black = NULL;
3044         r_texture_whitecube = NULL;
3045         r_texture_normalizationcube = NULL;
3046         r_texture_fogattenuation = NULL;
3047         r_texture_fogheighttexture = NULL;
3048         r_texture_gammaramps = NULL;
3049         r_texture_numcubemaps = 0;
3050         r_uniformbufferalignment = 32;
3051
3052         r_loaddds = r_texture_dds_load.integer != 0;
3053         r_savedds = vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3054
3055         switch(vid.renderpath)
3056         {
3057         case RENDERPATH_GL20:
3058         case RENDERPATH_GLES2:
3059                 Cvar_SetValueQuick(&r_textureunits, vid.texunits);
3060                 Cvar_SetValueQuick(&gl_combine, 1);
3061                 Cvar_SetValueQuick(&r_glsl, 1);
3062                 r_loadnormalmap = true;
3063                 r_loadgloss = true;
3064                 r_loadfog = false;
3065 #ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
3066                 if (vid.support.arb_uniform_buffer_object)
3067                         qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
3068 #endif
3069                         break;
3070         }
3071
3072         R_AnimCache_Free();
3073         R_FrameData_Reset();
3074         R_BufferData_Reset();
3075
3076         r_numqueries = 0;
3077         r_maxqueries = 0;
3078         memset(r_queries, 0, sizeof(r_queries));
3079
3080         r_qwskincache = NULL;
3081         r_qwskincache_size = 0;
3082
3083         // due to caching of texture_t references, the collision cache must be reset
3084         Collision_Cache_Reset(true);
3085
3086         // set up r_skinframe loading system for textures
3087         memset(&r_skinframe, 0, sizeof(r_skinframe));
3088         r_skinframe.loadsequence = 1;
3089         Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
3090
3091         r_main_texturepool = R_AllocTexturePool();
3092         R_BuildBlankTextures();
3093         R_BuildNoTexture();
3094         if (vid.support.arb_texture_cube_map)
3095         {
3096                 R_BuildWhiteCube();
3097                 R_BuildNormalizationCube();
3098         }
3099         r_texture_fogattenuation = NULL;
3100         r_texture_fogheighttexture = NULL;
3101         r_texture_gammaramps = NULL;
3102         //r_texture_fogintensity = NULL;
3103         memset(&r_fb, 0, sizeof(r_fb));
3104         Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
3105         r_glsl_permutation = NULL;
3106         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3107         Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
3108         memset(&r_svbsp, 0, sizeof (r_svbsp));
3109
3110         memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
3111         r_texture_numcubemaps = 0;
3112
3113         r_refdef.fogmasktable_density = 0;
3114
3115 #ifdef __ANDROID__
3116         // For Steelstorm Android
3117         // FIXME CACHE the program and reload
3118         // FIXME see possible combinations for SS:BR android
3119         Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
3120         R_SetupShader_SetPermutationGLSL(0, 12);
3121         R_SetupShader_SetPermutationGLSL(0, 13);
3122         R_SetupShader_SetPermutationGLSL(0, 8388621);
3123         R_SetupShader_SetPermutationGLSL(3, 0);
3124         R_SetupShader_SetPermutationGLSL(3, 2048);
3125         R_SetupShader_SetPermutationGLSL(5, 0);
3126         R_SetupShader_SetPermutationGLSL(5, 2);
3127         R_SetupShader_SetPermutationGLSL(5, 2048);
3128         R_SetupShader_SetPermutationGLSL(5, 8388608);
3129         R_SetupShader_SetPermutationGLSL(11, 1);
3130         R_SetupShader_SetPermutationGLSL(11, 2049);
3131         R_SetupShader_SetPermutationGLSL(11, 8193);
3132         R_SetupShader_SetPermutationGLSL(11, 10241);
3133         Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
3134 #endif
3135 }
3136
3137 static void gl_main_shutdown(void)
3138 {
3139         R_RenderTarget_FreeUnused(true);
3140         Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
3141         R_AnimCache_Free();
3142         R_FrameData_Reset();
3143         R_BufferData_Reset();
3144
3145         R_Main_FreeViewCache();
3146
3147         switch(vid.renderpath)
3148         {
3149         case RENDERPATH_GL20:
3150         case RENDERPATH_GLES2:
3151 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
3152                 if (r_maxqueries)
3153                         qglDeleteQueriesARB(r_maxqueries, r_queries);
3154 #endif
3155                 break;
3156         }
3157
3158         r_numqueries = 0;
3159         r_maxqueries = 0;
3160         memset(r_queries, 0, sizeof(r_queries));
3161
3162         r_qwskincache = NULL;
3163         r_qwskincache_size = 0;
3164
3165         // clear out the r_skinframe state
3166         Mem_ExpandableArray_FreeArray(&r_skinframe.array);
3167         memset(&r_skinframe, 0, sizeof(r_skinframe));
3168
3169         if (r_svbsp.nodes)
3170                 Mem_Free(r_svbsp.nodes);
3171         memset(&r_svbsp, 0, sizeof (r_svbsp));
3172         R_FreeTexturePool(&r_main_texturepool);
3173         loadingscreentexture = NULL;
3174         r_texture_blanknormalmap = NULL;
3175         r_texture_white = NULL;
3176         r_texture_grey128 = NULL;
3177         r_texture_black = NULL;
3178         r_texture_whitecube = NULL;
3179         r_texture_normalizationcube = NULL;
3180         r_texture_fogattenuation = NULL;
3181         r_texture_fogheighttexture = NULL;
3182         r_texture_gammaramps = NULL;
3183         r_texture_numcubemaps = 0;
3184         //r_texture_fogintensity = NULL;
3185         memset(&r_fb, 0, sizeof(r_fb));
3186         R_GLSL_Restart_f();
3187
3188         r_glsl_permutation = NULL;
3189         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3190         Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
3191 }
3192
3193 static void gl_main_newmap(void)
3194 {
3195         // FIXME: move this code to client
3196         char *entities, entname[MAX_QPATH];
3197         if (r_qwskincache)
3198                 Mem_Free(r_qwskincache);
3199         r_qwskincache = NULL;
3200         r_qwskincache_size = 0;
3201         if (cl.worldmodel)
3202         {
3203                 dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension);
3204                 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
3205                 {
3206                         CL_ParseEntityLump(entities);
3207                         Mem_Free(entities);
3208                         return;
3209                 }
3210                 if (cl.worldmodel->brush.entities)
3211                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
3212         }
3213         R_Main_FreeViewCache();
3214
3215         R_FrameData_Reset();
3216         R_BufferData_Reset();
3217 }
3218
3219 void GL_Main_Init(void)
3220 {
3221         int i;
3222         r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
3223         R_InitShaderModeInfo();
3224
3225         Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
3226         Cmd_AddCommand("r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
3227         // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
3228         if (gamemode == GAME_NEHAHRA)
3229         {
3230                 Cvar_RegisterVariable (&gl_fogenable);
3231                 Cvar_RegisterVariable (&gl_fogdensity);
3232                 Cvar_RegisterVariable (&gl_fogred);
3233                 Cvar_RegisterVariable (&gl_foggreen);
3234                 Cvar_RegisterVariable (&gl_fogblue);
3235                 Cvar_RegisterVariable (&gl_fogstart);
3236                 Cvar_RegisterVariable (&gl_fogend);
3237                 Cvar_RegisterVariable (&gl_skyclip);
3238         }
3239         Cvar_RegisterVariable(&r_motionblur);
3240         Cvar_RegisterVariable(&r_damageblur);
3241         Cvar_RegisterVariable(&r_motionblur_averaging);
3242         Cvar_RegisterVariable(&r_motionblur_randomize);
3243         Cvar_RegisterVariable(&r_motionblur_minblur);
3244         Cvar_RegisterVariable(&r_motionblur_maxblur);
3245         Cvar_RegisterVariable(&r_motionblur_velocityfactor);
3246         Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed);
3247         Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed);
3248         Cvar_RegisterVariable(&r_motionblur_mousefactor);
3249         Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed);
3250         Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed);
3251         Cvar_RegisterVariable(&r_equalize_entities_fullbright);
3252         Cvar_RegisterVariable(&r_equalize_entities_minambient);
3253         Cvar_RegisterVariable(&r_equalize_entities_by);
3254         Cvar_RegisterVariable(&r_equalize_entities_to);
3255         Cvar_RegisterVariable(&r_depthfirst);
3256         Cvar_RegisterVariable(&r_useinfinitefarclip);
3257         Cvar_RegisterVariable(&r_farclip_base);
3258         Cvar_RegisterVariable(&r_farclip_world);
3259         Cvar_RegisterVariable(&r_nearclip);
3260         Cvar_RegisterVariable(&r_deformvertexes);
3261         Cvar_RegisterVariable(&r_transparent);
3262         Cvar_RegisterVariable(&r_transparent_alphatocoverage);
3263         Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
3264         Cvar_RegisterVariable(&r_transparent_useplanardistance);
3265         Cvar_RegisterVariable(&r_showoverdraw);
3266         Cvar_RegisterVariable(&r_showbboxes);
3267         Cvar_RegisterVariable(&r_showbboxes_client);
3268         Cvar_RegisterVariable(&r_showsurfaces);
3269         Cvar_RegisterVariable(&r_showtris);
3270         Cvar_RegisterVariable(&r_shownormals);
3271         Cvar_RegisterVariable(&r_showlighting);
3272         Cvar_RegisterVariable(&r_showcollisionbrushes);
3273         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
3274         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
3275         Cvar_RegisterVariable(&r_showdisabledepthtest);
3276         Cvar_RegisterVariable(&r_showspriteedges);
3277         Cvar_RegisterVariable(&r_showparticleedges);
3278         Cvar_RegisterVariable(&r_drawportals);
3279         Cvar_RegisterVariable(&r_drawentities);
3280         Cvar_RegisterVariable(&r_draw2d);
3281         Cvar_RegisterVariable(&r_drawworld);
3282         Cvar_RegisterVariable(&r_cullentities_trace);
3283         Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
3284         Cvar_RegisterVariable(&r_cullentities_trace_samples);
3285         Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
3286         Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
3287         Cvar_RegisterVariable(&r_cullentities_trace_expand);
3288         Cvar_RegisterVariable(&r_cullentities_trace_pad);
3289         Cvar_RegisterVariable(&r_cullentities_trace_delay);
3290         Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
3291         Cvar_RegisterVariable(&r_sortentities);
3292         Cvar_RegisterVariable(&r_drawviewmodel);
3293         Cvar_RegisterVariable(&r_drawexteriormodel);
3294         Cvar_RegisterVariable(&r_speeds);
3295         Cvar_RegisterVariable(&r_fullbrights);
3296         Cvar_RegisterVariable(&r_wateralpha);
3297         Cvar_RegisterVariable(&r_dynamic);
3298         Cvar_RegisterVariable(&r_fakelight);
3299         Cvar_RegisterVariable(&r_fakelight_intensity);
3300         Cvar_RegisterVariable(&r_fullbright_directed);
3301         Cvar_RegisterVariable(&r_fullbright_directed_ambient);
3302         Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
3303         Cvar_RegisterVariable(&r_fullbright_directed_pitch);
3304         Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
3305         Cvar_RegisterVariable(&r_fullbright);
3306         Cvar_RegisterVariable(&r_shadows);
3307         Cvar_RegisterVariable(&r_shadows_darken);
3308         Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
3309         Cvar_RegisterVariable(&r_shadows_castfrombmodels);
3310         Cvar_RegisterVariable(&r_shadows_throwdistance);
3311         Cvar_RegisterVariable(&r_shadows_throwdirection);
3312         Cvar_RegisterVariable(&r_shadows_focus);
3313         Cvar_RegisterVariable(&r_shadows_shadowmapscale);
3314         Cvar_RegisterVariable(&r_shadows_shadowmapbias);
3315         Cvar_RegisterVariable(&r_q1bsp_skymasking);
3316         Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
3317         Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
3318         Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
3319         Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
3320         Cvar_RegisterVariable(&r_fog_exp2);
3321         Cvar_RegisterVariable(&r_fog_clear);
3322         Cvar_RegisterVariable(&r_drawfog);
3323         Cvar_RegisterVariable(&r_transparentdepthmasking);
3324         Cvar_RegisterVariable(&r_transparent_sortmindist);
3325         Cvar_RegisterVariable(&r_transparent_sortmaxdist);
3326         Cvar_RegisterVariable(&r_transparent_sortarraysize);
3327         Cvar_RegisterVariable(&r_texture_dds_load);
3328         Cvar_RegisterVariable(&r_texture_dds_save);
3329         Cvar_RegisterVariable(&r_textureunits);
3330         Cvar_RegisterVariable(&gl_combine);
3331         Cvar_RegisterVariable(&r_usedepthtextures);
3332         Cvar_RegisterVariable(&r_viewfbo);
3333         Cvar_RegisterVariable(&r_rendertarget_debug);
3334         Cvar_RegisterVariable(&r_viewscale);
3335         Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3336         Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3337         Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3338         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3339         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3340         Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3341         Cvar_RegisterVariable(&r_glsl);
3342         Cvar_RegisterVariable(&r_glsl_deluxemapping);
3343         Cvar_RegisterVariable(&r_glsl_offsetmapping);
3344         Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3345         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3346         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3347         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3348         Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3349         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3350         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3351         Cvar_RegisterVariable(&r_glsl_postprocess);
3352         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3353         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3354         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3355         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3356         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3357         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3358         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3359         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3360         Cvar_RegisterVariable(&r_celshading);
3361         Cvar_RegisterVariable(&r_celoutlines);
3362
3363         Cvar_RegisterVariable(&r_water);
3364         Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3365         Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3366         Cvar_RegisterVariable(&r_water_clippingplanebias);
3367         Cvar_RegisterVariable(&r_water_refractdistort);
3368         Cvar_RegisterVariable(&r_water_reflectdistort);
3369         Cvar_RegisterVariable(&r_water_scissormode);
3370         Cvar_RegisterVariable(&r_water_lowquality);
3371         Cvar_RegisterVariable(&r_water_hideplayer);
3372
3373         Cvar_RegisterVariable(&r_lerpsprites);
3374         Cvar_RegisterVariable(&r_lerpmodels);
3375         Cvar_RegisterVariable(&r_lerplightstyles);
3376         Cvar_RegisterVariable(&r_waterscroll);
3377         Cvar_RegisterVariable(&r_bloom);
3378         Cvar_RegisterVariable(&r_bloom_colorscale);
3379         Cvar_RegisterVariable(&r_bloom_brighten);
3380         Cvar_RegisterVariable(&r_bloom_blur);
3381         Cvar_RegisterVariable(&r_bloom_resolution);
3382         Cvar_RegisterVariable(&r_bloom_colorexponent);
3383         Cvar_RegisterVariable(&r_bloom_colorsubtract);
3384         Cvar_RegisterVariable(&r_bloom_scenebrightness);
3385         Cvar_RegisterVariable(&r_hdr_scenebrightness);
3386         Cvar_RegisterVariable(&r_hdr_glowintensity);
3387         Cvar_RegisterVariable(&r_hdr_irisadaptation);
3388         Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3389         Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3390         Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3391         Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3392         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3393         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3394         Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3395         Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3396         Cvar_RegisterVariable(&developer_texturelogging);
3397         Cvar_RegisterVariable(&gl_lightmaps);
3398         Cvar_RegisterVariable(&r_test);
3399         Cvar_RegisterVariable(&r_batch_multidraw);
3400         Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3401         Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3402         Cvar_RegisterVariable(&r_glsl_skeletal);
3403         Cvar_RegisterVariable(&r_glsl_saturation);
3404         Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3405         Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3406         Cvar_RegisterVariable(&r_framedatasize);
3407         for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3408                 Cvar_RegisterVariable(&r_buffermegs[i]);
3409         Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3410         if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3411                 Cvar_SetValue("r_fullbrights", 0);
3412 #ifdef DP_MOBILETOUCH
3413         // GLES devices have terrible depth precision in general, so...
3414         Cvar_SetValueQuick(&r_nearclip, 4);
3415         Cvar_SetValueQuick(&r_farclip_base, 4096);
3416         Cvar_SetValueQuick(&r_farclip_world, 0);
3417         Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3418 #endif
3419         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3420 }
3421
3422 void Render_Init(void)
3423 {
3424         gl_backend_init();
3425         R_Textures_Init();
3426         GL_Main_Init();
3427         Font_Init();
3428         GL_Draw_Init();
3429         R_Shadow_Init();
3430         R_Sky_Init();
3431         GL_Surf_Init();
3432         Sbar_Init();
3433         R_Particles_Init();
3434         R_Explosion_Init();
3435         R_LightningBeams_Init();
3436         Mod_RenderInit();
3437 }
3438
3439 /*
3440 ===============
3441 GL_Init
3442 ===============
3443 */
3444 #ifndef USE_GLES2
3445 extern char *ENGINE_EXTENSIONS;
3446 void GL_Init (void)
3447 {
3448         gl_renderer = (const char *)qglGetString(GL_RENDERER);
3449         gl_vendor = (const char *)qglGetString(GL_VENDOR);
3450         gl_version = (const char *)qglGetString(GL_VERSION);
3451         gl_extensions = (const char *)qglGetString(GL_EXTENSIONS);
3452
3453         if (!gl_extensions)
3454                 gl_extensions = "";
3455         if (!gl_platformextensions)
3456                 gl_platformextensions = "";
3457
3458         Con_Printf("GL_VENDOR: %s\n", gl_vendor);
3459         Con_Printf("GL_RENDERER: %s\n", gl_renderer);
3460         Con_Printf("GL_VERSION: %s\n", gl_version);
3461         Con_DPrintf("GL_EXTENSIONS: %s\n", gl_extensions);
3462         Con_DPrintf("%s_EXTENSIONS: %s\n", gl_platform, gl_platformextensions);
3463
3464         VID_CheckExtensions();
3465
3466         // LordHavoc: report supported extensions
3467 #ifdef CONFIG_MENU
3468         Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions );
3469 #else
3470         Con_DPrintf("\nQuakeC extensions for server and client: %s\n", vm_sv_extensions );
3471 #endif
3472
3473         // clear to black (loading plaque will be seen over this)
3474         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0);
3475 }
3476 #endif
3477
3478 int R_CullBox(const vec3_t mins, const vec3_t maxs)
3479 {
3480         int i;
3481         mplane_t *p;
3482         if (r_trippy.integer)
3483                 return false;
3484         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
3485         {
3486                 p = r_refdef.view.frustum + i;
3487                 switch(p->signbits)
3488                 {
3489                 default:
3490                 case 0:
3491                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3492                                 return true;
3493                         break;
3494                 case 1:
3495                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3496                                 return true;
3497                         break;
3498                 case 2:
3499                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3500                                 return true;
3501                         break;
3502                 case 3:
3503                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3504                                 return true;
3505                         break;
3506                 case 4:
3507                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3508                                 return true;
3509                         break;
3510                 case 5:
3511                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3512                                 return true;
3513                         break;
3514                 case 6:
3515                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3516                                 return true;
3517                         break;
3518                 case 7:
3519                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3520                                 return true;
3521                         break;
3522                 }
3523         }
3524         return false;
3525 }
3526
3527 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3528 {
3529         int i;
3530         const mplane_t *p;
3531         if (r_trippy.integer)
3532                 return false;
3533         for (i = 0;i < numplanes;i++)
3534         {
3535                 p = planes + i;
3536                 switch(p->signbits)
3537                 {
3538                 default:
3539                 case 0:
3540                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3541                                 return true;
3542                         break;
3543                 case 1:
3544                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3545                                 return true;
3546                         break;
3547                 case 2:
3548                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3549                                 return true;
3550                         break;
3551                 case 3:
3552                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3553                                 return true;
3554                         break;
3555                 case 4:
3556                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3557                                 return true;
3558                         break;
3559                 case 5:
3560                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3561                                 return true;
3562                         break;
3563                 case 6:
3564                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3565                                 return true;
3566                         break;
3567                 case 7:
3568                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3569                                 return true;
3570                         break;
3571                 }
3572         }
3573         return false;
3574 }
3575
3576 //==================================================================================
3577
3578 // LordHavoc: this stores temporary data used within the same frame
3579
3580 typedef struct r_framedata_mem_s
3581 {
3582         struct r_framedata_mem_s *purge; // older mem block to free on next frame
3583         size_t size; // how much usable space
3584         size_t current; // how much space in use
3585         size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3586         size_t wantedsize; // how much space was allocated
3587         unsigned char *data; // start of real data (16byte aligned)
3588 }
3589 r_framedata_mem_t;
3590
3591 static r_framedata_mem_t *r_framedata_mem;
3592
3593 void R_FrameData_Reset(void)
3594 {
3595         while (r_framedata_mem)
3596         {
3597                 r_framedata_mem_t *next = r_framedata_mem->purge;
3598                 Mem_Free(r_framedata_mem);
3599                 r_framedata_mem = next;
3600         }
3601 }
3602
3603 static void R_FrameData_Resize(qboolean mustgrow)
3604 {
3605         size_t wantedsize;
3606         wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3607         wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3608         if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3609         {
3610                 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3611                 newmem->wantedsize = wantedsize;
3612                 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3613                 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3614                 newmem->current = 0;
3615                 newmem->mark = 0;
3616                 newmem->purge = r_framedata_mem;
3617                 r_framedata_mem = newmem;
3618         }
3619 }
3620
3621 void R_FrameData_NewFrame(void)
3622 {
3623         R_FrameData_Resize(false);
3624         if (!r_framedata_mem)
3625                 return;
3626         // if we ran out of space on the last frame, free the old memory now
3627         while (r_framedata_mem->purge)
3628         {
3629                 // repeatedly remove the second item in the list, leaving only head
3630                 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3631                 Mem_Free(r_framedata_mem->purge);
3632                 r_framedata_mem->purge = next;
3633         }
3634         // reset the current mem pointer
3635         r_framedata_mem->current = 0;
3636         r_framedata_mem->mark = 0;
3637 }
3638
3639 void *R_FrameData_Alloc(size_t size)
3640 {
3641         void *data;
3642         float newvalue;
3643
3644         // align to 16 byte boundary - the data pointer is already aligned, so we
3645         // only need to ensure the size of every allocation is also aligned
3646         size = (size + 15) & ~15;
3647
3648         while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3649         {
3650                 // emergency - we ran out of space, allocate more memory
3651                 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3652                 newvalue = r_framedatasize.value * 2.0f;
3653                 // 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
3654                 if (sizeof(size_t) >= 8)
3655                         newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3656                 else
3657                         newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3658                 // this might not be a growing it, but we'll allocate another buffer every time
3659                 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3660                 R_FrameData_Resize(true);
3661         }
3662
3663         data = r_framedata_mem->data + r_framedata_mem->current;
3664         r_framedata_mem->current += size;
3665
3666         // count the usage for stats
3667         r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3668         r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3669
3670         return (void *)data;
3671 }
3672
3673 void *R_FrameData_Store(size_t size, void *data)
3674 {
3675         void *d = R_FrameData_Alloc(size);
3676         if (d && data)
3677                 memcpy(d, data, size);
3678         return d;
3679 }
3680
3681 void R_FrameData_SetMark(void)
3682 {
3683         if (!r_framedata_mem)
3684                 return;
3685         r_framedata_mem->mark = r_framedata_mem->current;
3686 }
3687
3688 void R_FrameData_ReturnToMark(void)
3689 {
3690         if (!r_framedata_mem)
3691                 return;
3692         r_framedata_mem->current = r_framedata_mem->mark;
3693 }
3694
3695 //==================================================================================
3696
3697 // avoid reusing the same buffer objects on consecutive frames
3698 #define R_BUFFERDATA_CYCLE 3
3699
3700 typedef struct r_bufferdata_buffer_s
3701 {
3702         struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3703         size_t size; // how much usable space
3704         size_t current; // how much space in use
3705         r_meshbuffer_t *buffer; // the buffer itself
3706 }
3707 r_bufferdata_buffer_t;
3708
3709 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3710 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3711
3712 /// frees all dynamic buffers
3713 void R_BufferData_Reset(void)
3714 {
3715         int cycle, type;
3716         r_bufferdata_buffer_t **p, *mem;
3717         for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3718         {
3719                 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3720                 {
3721                         // free all buffers
3722                         p = &r_bufferdata_buffer[cycle][type];
3723                         while (*p)
3724                         {
3725                                 mem = *p;
3726                                 *p = (*p)->purge;
3727                                 if (mem->buffer)
3728                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3729                                 Mem_Free(mem);
3730                         }
3731                 }
3732         }
3733 }
3734
3735 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3736 static void R_BufferData_Resize(r_bufferdata_type_t type, qboolean mustgrow, size_t minsize)
3737 {
3738         r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3739         size_t size;
3740         float newvalue = r_buffermegs[type].value;
3741
3742         // increase the cvar if we have to (but only if we already have a mem)
3743         if (mustgrow && mem)
3744                 newvalue *= 2.0f;
3745         newvalue = bound(0.25f, newvalue, 256.0f);
3746         while (newvalue * 1024*1024 < minsize)
3747                 newvalue *= 2.0f;
3748
3749         // clamp the cvar to valid range
3750         newvalue = bound(0.25f, newvalue, 256.0f);
3751         if (r_buffermegs[type].value != newvalue)
3752                 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3753
3754         // calculate size in bytes
3755         size = (size_t)(newvalue * 1024*1024);
3756         size = bound(131072, size, 256*1024*1024);
3757
3758         // allocate a new buffer if the size is different (purge old one later)
3759         // or if we were told we must grow the buffer
3760         if (!mem || mem->size != size || mustgrow)
3761         {
3762                 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3763                 mem->size = size;
3764                 mem->current = 0;
3765                 if (type == R_BUFFERDATA_VERTEX)
3766                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3767                 else if (type == R_BUFFERDATA_INDEX16)
3768                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3769                 else if (type == R_BUFFERDATA_INDEX32)
3770                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3771                 else if (type == R_BUFFERDATA_UNIFORM)
3772                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3773                 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3774                 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3775         }
3776 }
3777
3778 void R_BufferData_NewFrame(void)
3779 {
3780         int type;
3781         r_bufferdata_buffer_t **p, *mem;
3782         // cycle to the next frame's buffers
3783         r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3784         // if we ran out of space on the last time we used these buffers, free the old memory now
3785         for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3786         {
3787                 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3788                 {
3789                         R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3790                         // free all but the head buffer, this is how we recycle obsolete
3791                         // buffers after they are no longer in use
3792                         p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3793                         while (*p)
3794                         {
3795                                 mem = *p;
3796                                 *p = (*p)->purge;
3797                                 if (mem->buffer)
3798                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3799                                 Mem_Free(mem);
3800                         }
3801                         // reset the current offset
3802                         r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3803                 }
3804         }
3805 }
3806
3807 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3808 {
3809         r_bufferdata_buffer_t *mem;
3810         int offset = 0;
3811         int padsize;
3812
3813         *returnbufferoffset = 0;
3814
3815         // align size to a byte boundary appropriate for the buffer type, this
3816         // makes all allocations have aligned start offsets
3817         if (type == R_BUFFERDATA_UNIFORM)
3818                 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3819         else
3820                 padsize = (datasize + 15) & ~15;
3821
3822         // if we ran out of space in this buffer we must allocate a new one
3823         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)
3824                 R_BufferData_Resize(type, true, padsize);
3825
3826         // if the resize did not give us enough memory, fail
3827         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)
3828                 Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3829
3830         mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3831         offset = (int)mem->current;
3832         mem->current += padsize;
3833
3834         // upload the data to the buffer at the chosen offset
3835         if (offset == 0)
3836                 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3837         R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3838
3839         // count the usage for stats
3840         r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3841         r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3842
3843         // return the buffer offset
3844         *returnbufferoffset = offset;
3845
3846         return mem->buffer;
3847 }
3848
3849 //==================================================================================
3850
3851 // LordHavoc: animcache originally written by Echon, rewritten since then
3852
3853 /**
3854  * Animation cache prevents re-generating mesh data for an animated model
3855  * multiple times in one frame for lighting, shadowing, reflections, etc.
3856  */
3857
3858 void R_AnimCache_Free(void)
3859 {
3860 }
3861
3862 void R_AnimCache_ClearCache(void)
3863 {
3864         int i;
3865         entity_render_t *ent;
3866
3867         for (i = 0;i < r_refdef.scene.numentities;i++)
3868         {
3869                 ent = r_refdef.scene.entities[i];
3870                 ent->animcache_vertex3f = NULL;
3871                 ent->animcache_vertex3f_vertexbuffer = NULL;
3872                 ent->animcache_vertex3f_bufferoffset = 0;
3873                 ent->animcache_normal3f = NULL;
3874                 ent->animcache_normal3f_vertexbuffer = NULL;
3875                 ent->animcache_normal3f_bufferoffset = 0;
3876                 ent->animcache_svector3f = NULL;
3877                 ent->animcache_svector3f_vertexbuffer = NULL;
3878                 ent->animcache_svector3f_bufferoffset = 0;
3879                 ent->animcache_tvector3f = NULL;
3880                 ent->animcache_tvector3f_vertexbuffer = NULL;
3881                 ent->animcache_tvector3f_bufferoffset = 0;
3882                 ent->animcache_vertexmesh = NULL;
3883                 ent->animcache_vertexmesh_vertexbuffer = NULL;
3884                 ent->animcache_vertexmesh_bufferoffset = 0;
3885                 ent->animcache_skeletaltransform3x4 = NULL;
3886                 ent->animcache_skeletaltransform3x4buffer = NULL;
3887                 ent->animcache_skeletaltransform3x4offset = 0;
3888                 ent->animcache_skeletaltransform3x4size = 0;
3889         }
3890 }
3891
3892 static void R_AnimCache_UpdateEntityMeshBuffers(entity_render_t *ent, int numvertices)
3893 {
3894         int i;
3895
3896         // check if we need the meshbuffers
3897         if (!vid.useinterleavedarrays)
3898                 return;
3899
3900         if (!ent->animcache_vertexmesh && ent->animcache_normal3f)
3901                 ent->animcache_vertexmesh = (r_vertexmesh_t *)R_FrameData_Alloc(sizeof(r_vertexmesh_t)*numvertices);
3902         // TODO: upload vertexbuffer?
3903         if (ent->animcache_vertexmesh)
3904         {
3905                 r_refdef.stats[r_stat_animcache_vertexmesh_count] += 1;
3906                 r_refdef.stats[r_stat_animcache_vertexmesh_vertices] += numvertices;
3907                 r_refdef.stats[r_stat_animcache_vertexmesh_maxvertices] = max(r_refdef.stats[r_stat_animcache_vertexmesh_maxvertices], numvertices);
3908                 memcpy(ent->animcache_vertexmesh, ent->model->surfmesh.data_vertexmesh, sizeof(r_vertexmesh_t)*numvertices);
3909                 for (i = 0;i < numvertices;i++)
3910                         memcpy(ent->animcache_vertexmesh[i].vertex3f, ent->animcache_vertex3f + 3*i, sizeof(float[3]));
3911                 if (ent->animcache_svector3f)
3912                         for (i = 0;i < numvertices;i++)
3913                                 memcpy(ent->animcache_vertexmesh[i].svector3f, ent->animcache_svector3f + 3*i, sizeof(float[3]));
3914                 if (ent->animcache_tvector3f)
3915                         for (i = 0;i < numvertices;i++)
3916                                 memcpy(ent->animcache_vertexmesh[i].tvector3f, ent->animcache_tvector3f + 3*i, sizeof(float[3]));
3917                 if (ent->animcache_normal3f)
3918                         for (i = 0;i < numvertices;i++)
3919                                 memcpy(ent->animcache_vertexmesh[i].normal3f, ent->animcache_normal3f + 3*i, sizeof(float[3]));
3920         }
3921 }
3922
3923 qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
3924 {
3925         dp_model_t *model = ent->model;
3926         int numvertices;
3927
3928         // see if this ent is worth caching
3929         if (!model || !model->Draw || !model->AnimateVertices)
3930                 return false;
3931         // nothing to cache if it contains no animations and has no skeleton
3932         if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3933                 return false;
3934         // see if it is already cached for gpuskeletal
3935         if (ent->animcache_skeletaltransform3x4)
3936                 return false;
3937         // see if it is already cached as a mesh
3938         if (ent->animcache_vertex3f)
3939         {
3940                 // check if we need to add normals or tangents
3941                 if (ent->animcache_normal3f)
3942                         wantnormals = false;
3943                 if (ent->animcache_svector3f)
3944                         wanttangents = false;
3945                 if (!wantnormals && !wanttangents)
3946                         return false;
3947         }
3948
3949         // check which kind of cache we need to generate
3950         if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3951         {
3952                 // cache the skeleton so the vertex shader can use it
3953                 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3954                 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3955                 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3956                 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3957                 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4); 
3958                 // note: this can fail if the buffer is at the grow limit
3959                 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3960                 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3961         }
3962         else if (ent->animcache_vertex3f)
3963         {
3964                 // mesh was already cached but we may need to add normals/tangents
3965                 // (this only happens with multiple views, reflections, cameras, etc)
3966                 if (wantnormals || wanttangents)
3967                 {
3968                         numvertices = model->surfmesh.num_vertices;
3969                         if (wantnormals)
3970                                 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3971                         if (wanttangents)
3972                         {
3973                                 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3974                                 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3975                         }
3976                         model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3977                         R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices);
3978                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3979                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3980                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3981                 }
3982         }
3983         else
3984         {
3985                 // generate mesh cache
3986                 numvertices = model->surfmesh.num_vertices;
3987                 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
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, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
3996                 R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices);
3997                 if (wantnormals || wanttangents)
3998                 {
3999                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
4000                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
4001                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
4002                 }
4003                 r_refdef.stats[r_stat_animcache_shape_count] += 1;
4004                 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
4005                 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
4006         }
4007         return true;
4008 }
4009
4010 void R_AnimCache_CacheVisibleEntities(void)
4011 {
4012         int i;
4013
4014         // TODO: thread this
4015         // NOTE: R_PrepareRTLights() also caches entities
4016
4017         for (i = 0;i < r_refdef.scene.numentities;i++)
4018                 if (r_refdef.viewcache.entityvisible[i])
4019                         R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
4020 }
4021
4022 //==================================================================================
4023
4024 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)
4025 {
4026         int i;
4027         vec3_t eyemins, eyemaxs;
4028         vec3_t boxmins, boxmaxs;
4029         vec3_t padmins, padmaxs;
4030         vec3_t start;
4031         vec3_t end;
4032         dp_model_t *model = r_refdef.scene.worldmodel;
4033         static vec3_t positions[] = {
4034                 { 0.5f, 0.5f, 0.5f },
4035                 { 0.0f, 0.0f, 0.0f },
4036                 { 0.0f, 0.0f, 1.0f },
4037                 { 0.0f, 1.0f, 0.0f },
4038                 { 0.0f, 1.0f, 1.0f },
4039                 { 1.0f, 0.0f, 0.0f },
4040                 { 1.0f, 0.0f, 1.0f },
4041                 { 1.0f, 1.0f, 0.0f },
4042                 { 1.0f, 1.0f, 1.0f },
4043         };
4044
4045         // sample count can be set to -1 to skip this logic, for flicker-prone objects
4046         if (numsamples < 0)
4047                 return true;
4048
4049         // view origin is not used for culling in portal/reflection/refraction renders or isometric views
4050         if (!r_refdef.view.usevieworiginculling)
4051                 return true;
4052
4053         if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
4054                 return true;
4055
4056         // expand the eye box a little
4057         eyemins[0] = eye[0] - eyejitter;
4058         eyemaxs[0] = eye[0] + eyejitter;
4059         eyemins[1] = eye[1] - eyejitter;
4060         eyemaxs[1] = eye[1] + eyejitter;
4061         eyemins[2] = eye[2] - eyejitter;
4062         eyemaxs[2] = eye[2] + eyejitter;
4063         // expand the box a little
4064         boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
4065         boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
4066         boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
4067         boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
4068         boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
4069         boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
4070         // make an even larger box for the acceptable area
4071         padmins[0] = boxmins[0] - pad;
4072         padmaxs[0] = boxmaxs[0] + pad;
4073         padmins[1] = boxmins[1] - pad;
4074         padmaxs[1] = boxmaxs[1] + pad;
4075         padmins[2] = boxmins[2] - pad;
4076         padmaxs[2] = boxmaxs[2] + pad;
4077
4078         // return true if eye overlaps enlarged box
4079         if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
4080                 return true;
4081
4082         // try specific positions in the box first - note that these can be cached
4083         if (r_cullentities_trace_entityocclusion.integer)
4084         {
4085                 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
4086                 {
4087                         VectorCopy(eye, start);
4088                         end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
4089                         end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
4090                         end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
4091                         //trace_t trace = CL_TraceLine(start, end, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, 0.0f, true, false, NULL, true, true);
4092                         trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
4093                         // not picky - if the trace ended anywhere in the box we're good
4094                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4095                                 return true;
4096                 }
4097         }
4098         else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4099                 return true;
4100
4101         // try various random positions
4102         for (i = 0; i < numsamples; i++)
4103         {
4104                 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
4105                 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
4106                 if (r_cullentities_trace_entityocclusion.integer)
4107                 {
4108                         trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
4109                         // not picky - if the trace ended anywhere in the box we're good
4110                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4111                                 return true;
4112                 }
4113                 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4114                         return true;
4115         }
4116
4117         return false;
4118 }
4119
4120
4121 static void R_View_UpdateEntityVisible (void)
4122 {
4123         int i;
4124         int renderimask;
4125         int samples;
4126         entity_render_t *ent;
4127
4128         if (r_refdef.envmap || r_fb.water.hideplayer)
4129                 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
4130         else if (chase_active.integer || r_fb.water.renderingscene)
4131                 renderimask = RENDER_VIEWMODEL;
4132         else
4133                 renderimask = RENDER_EXTERIORMODEL;
4134         if (!r_drawviewmodel.integer)
4135                 renderimask |= RENDER_VIEWMODEL;
4136         if (!r_drawexteriormodel.integer)
4137                 renderimask |= RENDER_EXTERIORMODEL;
4138         memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4139         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4140         {
4141                 // worldmodel can check visibility
4142                 for (i = 0;i < r_refdef.scene.numentities;i++)
4143                 {
4144                         ent = r_refdef.scene.entities[i];
4145                         if (!(ent->flags & renderimask))
4146                         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)))
4147                         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))
4148                                 r_refdef.viewcache.entityvisible[i] = true;
4149                 }
4150         }
4151         else
4152         {
4153                 // no worldmodel or it can't check visibility
4154                 for (i = 0;i < r_refdef.scene.numentities;i++)
4155                 {
4156                         ent = r_refdef.scene.entities[i];
4157                         if (!(ent->flags & renderimask))
4158                         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)))
4159                                 r_refdef.viewcache.entityvisible[i] = true;
4160                 }
4161         }
4162         if (r_cullentities_trace.integer)
4163         {
4164                 for (i = 0;i < r_refdef.scene.numentities;i++)
4165                 {
4166                         if (!r_refdef.viewcache.entityvisible[i])
4167                                 continue;
4168                         ent = r_refdef.scene.entities[i];
4169                         if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4170                         {
4171                                 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4172                                 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))
4173                                         ent->last_trace_visibility = realtime;
4174                                 if (ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
4175                                         r_refdef.viewcache.entityvisible[i] = 0;
4176                         }
4177                 }
4178         }
4179 }
4180
4181 /// only used if skyrendermasked, and normally returns false
4182 static int R_DrawBrushModelsSky (void)
4183 {
4184         int i, sky;
4185         entity_render_t *ent;
4186
4187         sky = false;
4188         for (i = 0;i < r_refdef.scene.numentities;i++)
4189         {
4190                 if (!r_refdef.viewcache.entityvisible[i])
4191                         continue;
4192                 ent = r_refdef.scene.entities[i];
4193                 if (!ent->model || !ent->model->DrawSky)
4194                         continue;
4195                 ent->model->DrawSky(ent);
4196                 sky = true;
4197         }
4198         return sky;
4199 }
4200
4201 static void R_DrawNoModel(entity_render_t *ent);
4202 static void R_DrawModels(void)
4203 {
4204         int i;
4205         entity_render_t *ent;
4206
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                 r_refdef.stats[r_stat_entities]++;
4213                 /*
4214                 if (ent->model && !strncmp(ent->model->name, "models/proto_", 13))
4215                 {
4216                         vec3_t f, l, u, o;
4217                         Matrix4x4_ToVectors(&ent->matrix, f, l, u, o);
4218                         Con_Printf("R_DrawModels\n");
4219                         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]);
4220                         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);
4221                         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);
4222                 }
4223                 */
4224                 if (ent->model && ent->model->Draw != NULL)
4225                         ent->model->Draw(ent);
4226                 else
4227                         R_DrawNoModel(ent);
4228         }
4229 }
4230
4231 static void R_DrawModelsDepth(void)
4232 {
4233         int i;
4234         entity_render_t *ent;
4235
4236         for (i = 0;i < r_refdef.scene.numentities;i++)
4237         {
4238                 if (!r_refdef.viewcache.entityvisible[i])
4239                         continue;
4240                 ent = r_refdef.scene.entities[i];
4241                 if (ent->model && ent->model->DrawDepth != NULL)
4242                         ent->model->DrawDepth(ent);
4243         }
4244 }
4245
4246 static void R_DrawModelsDebug(void)
4247 {
4248         int i;
4249         entity_render_t *ent;
4250
4251         for (i = 0;i < r_refdef.scene.numentities;i++)
4252         {
4253                 if (!r_refdef.viewcache.entityvisible[i])
4254                         continue;
4255                 ent = r_refdef.scene.entities[i];
4256                 if (ent->model && ent->model->DrawDebug != NULL)
4257                         ent->model->DrawDebug(ent);
4258         }
4259 }
4260
4261 static void R_DrawModelsAddWaterPlanes(void)
4262 {
4263         int i;
4264         entity_render_t *ent;
4265
4266         for (i = 0;i < r_refdef.scene.numentities;i++)
4267         {
4268                 if (!r_refdef.viewcache.entityvisible[i])
4269                         continue;
4270                 ent = r_refdef.scene.entities[i];
4271                 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4272                         ent->model->DrawAddWaterPlanes(ent);
4273         }
4274 }
4275
4276 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}};
4277
4278 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4279 {
4280         if (r_hdr_irisadaptation.integer)
4281         {
4282                 vec3_t p;
4283                 vec3_t ambient;
4284                 vec3_t diffuse;
4285                 vec3_t diffusenormal;
4286                 vec3_t forward;
4287                 vec_t brightness = 0.0f;
4288                 vec_t goal;
4289                 vec_t current;
4290                 vec_t d;
4291                 int c;
4292                 VectorCopy(r_refdef.view.forward, forward);
4293                 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4294                 {
4295                         p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4296                         p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4297                         p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4298                         R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4299                         d = DotProduct(forward, diffusenormal);
4300                         brightness += VectorLength(ambient);
4301                         if (d > 0)
4302                                 brightness += d * VectorLength(diffuse);
4303                 }
4304                 brightness *= 1.0f / c;
4305                 brightness += 0.00001f; // make sure it's never zero
4306                 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4307                 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4308                 current = r_hdr_irisadaptation_value.value;
4309                 if (current < goal)
4310                         current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4311                 else if (current > goal)
4312                         current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4313                 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4314                         Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4315         }
4316         else if (r_hdr_irisadaptation_value.value != 1.0f)
4317                 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4318 }
4319
4320 static void R_View_SetFrustum(const int *scissor)
4321 {
4322         int i;
4323         double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4324         vec3_t forward, left, up, origin, v;
4325
4326         if(scissor)
4327         {
4328                 // flipped x coordinates (because x points left here)
4329                 fpx =  1.0 - 2.0 * (scissor[0]              - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4330                 fnx =  1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4331                 // non-flipped y coordinates
4332                 fny = -1.0 + 2.0 * (scissor[1]              - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4333                 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4334         }
4335
4336         // we can't trust r_refdef.view.forward and friends in reflected scenes
4337         Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4338
4339 #if 0
4340         r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4341         r_refdef.view.frustum[0].normal[1] = 0 - 0;
4342         r_refdef.view.frustum[0].normal[2] = -1 - 0;
4343         r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4344         r_refdef.view.frustum[1].normal[1] = 0 + 0;
4345         r_refdef.view.frustum[1].normal[2] = -1 + 0;
4346         r_refdef.view.frustum[2].normal[0] = 0 - 0;
4347         r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4348         r_refdef.view.frustum[2].normal[2] = -1 - 0;
4349         r_refdef.view.frustum[3].normal[0] = 0 + 0;
4350         r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4351         r_refdef.view.frustum[3].normal[2] = -1 + 0;
4352 #endif
4353
4354 #if 0
4355         zNear = r_refdef.nearclip;
4356         nudge = 1.0 - 1.0 / (1<<23);
4357         r_refdef.view.frustum[4].normal[0] = 0 - 0;
4358         r_refdef.view.frustum[4].normal[1] = 0 - 0;
4359         r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4360         r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4361         r_refdef.view.frustum[5].normal[0] = 0 + 0;
4362         r_refdef.view.frustum[5].normal[1] = 0 + 0;
4363         r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4364         r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4365 #endif
4366
4367
4368
4369 #if 0
4370         r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4371         r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4372         r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4373         r_refdef.view.frustum[0].dist = m[15] - m[12];
4374
4375         r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4376         r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4377         r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4378         r_refdef.view.frustum[1].dist = m[15] + m[12];
4379
4380         r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4381         r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4382         r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4383         r_refdef.view.frustum[2].dist = m[15] - m[13];
4384
4385         r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4386         r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4387         r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4388         r_refdef.view.frustum[3].dist = m[15] + m[13];
4389
4390         r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4391         r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4392         r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4393         r_refdef.view.frustum[4].dist = m[15] - m[14];
4394
4395         r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4396         r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4397         r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4398         r_refdef.view.frustum[5].dist = m[15] + m[14];
4399 #endif
4400
4401         if (r_refdef.view.useperspective)
4402         {
4403                 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4404                 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]);
4405                 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]);
4406                 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]);
4407                 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]);
4408
4409                 // then the normals from the corners relative to origin
4410                 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4411                 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4412                 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4413                 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4414
4415                 // in a NORMAL view, forward cross left == up
4416                 // in a REFLECTED view, forward cross left == down
4417                 // so our cross products above need to be adjusted for a left handed coordinate system
4418                 CrossProduct(forward, left, v);
4419                 if(DotProduct(v, up) < 0)
4420                 {
4421                         VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4422                         VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4423                         VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4424                         VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4425                 }
4426
4427                 // Leaving those out was a mistake, those were in the old code, and they
4428                 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4429                 // I couldn't reproduce it after adding those normalizations. --blub
4430                 VectorNormalize(r_refdef.view.frustum[0].normal);
4431                 VectorNormalize(r_refdef.view.frustum[1].normal);
4432                 VectorNormalize(r_refdef.view.frustum[2].normal);
4433                 VectorNormalize(r_refdef.view.frustum[3].normal);
4434
4435                 // make the corners absolute
4436                 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4437                 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4438                 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4439                 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4440
4441                 // one more normal
4442                 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4443
4444                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4445                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4446                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4447                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4448                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4449         }
4450         else
4451         {
4452                 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4453                 VectorScale(left,  1.0f, r_refdef.view.frustum[1].normal);
4454                 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4455                 VectorScale(up,  1.0f, r_refdef.view.frustum[3].normal);
4456                 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4457                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4458                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4459                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4460                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4461                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4462         }
4463         r_refdef.view.numfrustumplanes = 5;
4464
4465         if (r_refdef.view.useclipplane)
4466         {
4467                 r_refdef.view.numfrustumplanes = 6;
4468                 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4469         }
4470
4471         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4472                 PlaneClassify(r_refdef.view.frustum + i);
4473
4474         // LordHavoc: note to all quake engine coders, Quake had a special case
4475         // for 90 degrees which assumed a square view (wrong), so I removed it,
4476         // Quake2 has it disabled as well.
4477
4478         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4479         //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4480         //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4481         //PlaneClassify(&frustum[0]);
4482
4483         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4484         //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4485         //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4486         //PlaneClassify(&frustum[1]);
4487
4488         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4489         //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4490         //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4491         //PlaneClassify(&frustum[2]);
4492
4493         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4494         //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4495         //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4496         //PlaneClassify(&frustum[3]);
4497
4498         // nearclip plane
4499         //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4500         //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4501         //PlaneClassify(&frustum[4]);
4502 }
4503
4504 static void R_View_UpdateWithScissor(const int *myscissor)
4505 {
4506         R_Main_ResizeViewCache();
4507         R_View_SetFrustum(myscissor);
4508         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4509         R_View_UpdateEntityVisible();
4510 }
4511
4512 static void R_View_Update(void)
4513 {
4514         R_Main_ResizeViewCache();
4515         R_View_SetFrustum(NULL);
4516         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4517         R_View_UpdateEntityVisible();
4518 }
4519
4520 float viewscalefpsadjusted = 1.0f;
4521
4522 static void R_GetScaledViewSize(int width, int height, int *outwidth, int *outheight)
4523 {
4524         float scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
4525         scale = bound(0.03125f, scale, 1.0f);
4526         *outwidth = (int)ceil(width * scale);
4527         *outheight = (int)ceil(height * scale);
4528 }
4529
4530 void R_SetupView(qboolean allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4531 {
4532         const float *customclipplane = NULL;
4533         float plane[4];
4534         int /*rtwidth,*/ rtheight;
4535         if (r_refdef.view.useclipplane && allowwaterclippingplane)
4536         {
4537                 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4538                 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4539                 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4540                 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4541                         dist = r_refdef.view.clipplane.dist;
4542                 plane[0] = r_refdef.view.clipplane.normal[0];
4543                 plane[1] = r_refdef.view.clipplane.normal[1];
4544                 plane[2] = r_refdef.view.clipplane.normal[2];
4545                 plane[3] = -dist;
4546                 customclipplane = plane;
4547         }
4548
4549         //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
4550         rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
4551
4552         if (!r_refdef.view.useperspective)
4553                 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);
4554         else if (vid.stencil && r_useinfinitefarclip.integer)
4555                 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);
4556         else
4557                 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);
4558         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4559         R_SetViewport(&r_refdef.view.viewport);
4560 }
4561
4562 void R_EntityMatrix(const matrix4x4_t *matrix)
4563 {
4564         if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4565         {
4566                 gl_modelmatrixchanged = false;
4567                 gl_modelmatrix = *matrix;
4568                 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4569                 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4570                 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4571                 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4572                 CHECKGLERROR
4573                 switch(vid.renderpath)
4574                 {
4575                 case RENDERPATH_GL20:
4576                 case RENDERPATH_GLES2:
4577                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4578                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4579                         break;
4580                 }
4581         }
4582 }
4583
4584 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4585 {
4586         r_viewport_t viewport;
4587
4588         CHECKGLERROR
4589
4590         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
4591         R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4592         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4593         R_SetViewport(&viewport);
4594         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4595         GL_Color(1, 1, 1, 1);
4596         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4597         GL_BlendFunc(GL_ONE, GL_ZERO);
4598         GL_ScissorTest(false);
4599         GL_DepthMask(false);
4600         GL_DepthRange(0, 1);
4601         GL_DepthTest(false);
4602         GL_DepthFunc(GL_LEQUAL);
4603         R_EntityMatrix(&identitymatrix);
4604         R_Mesh_ResetTextureState();
4605         GL_PolygonOffset(0, 0);
4606         switch(vid.renderpath)
4607         {
4608         case RENDERPATH_GL20:
4609         case RENDERPATH_GLES2:
4610                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4611                 break;
4612         }
4613         GL_CullFace(GL_NONE);
4614
4615         CHECKGLERROR
4616 }
4617
4618 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4619 {
4620         R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4621 }
4622
4623 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4624 {
4625         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4626         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4627         GL_Color(1, 1, 1, 1);
4628         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4629         GL_BlendFunc(GL_ONE, GL_ZERO);
4630         GL_ScissorTest(true);
4631         GL_DepthMask(true);
4632         GL_DepthRange(0, 1);
4633         GL_DepthTest(true);
4634         GL_DepthFunc(GL_LEQUAL);
4635         R_EntityMatrix(&identitymatrix);
4636         R_Mesh_ResetTextureState();
4637         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4638         switch(vid.renderpath)
4639         {
4640         case RENDERPATH_GL20:
4641         case RENDERPATH_GLES2:
4642                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4643                 break;
4644         }
4645         GL_CullFace(r_refdef.view.cullface_back);
4646 }
4647
4648 /*
4649 ================
4650 R_RenderView_UpdateViewVectors
4651 ================
4652 */
4653 void R_RenderView_UpdateViewVectors(void)
4654 {
4655         // break apart the view matrix into vectors for various purposes
4656         // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4657         // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4658         Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4659         VectorNegate(r_refdef.view.left, r_refdef.view.right);
4660         // make an inverted copy of the view matrix for tracking sprites
4661         Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4662 }
4663
4664 void R_RenderTarget_FreeUnused(qboolean force)
4665 {
4666         int i, j, end;
4667         end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
4668         for (i = 0; i < end; i++)
4669         {
4670                 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4671                 // free resources for rendertargets that have not been used for a while
4672                 // (note: this check is run after the frame render, so any targets used
4673                 // this frame will not be affected even at low framerates)
4674                 if (r && (realtime - r->lastusetime > 0.2 || force))
4675                 {
4676                         if (r->fbo)
4677                                 R_Mesh_DestroyFramebufferObject(r->fbo);
4678                         for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4679                                 if (r->colortexture[j])
4680                                         R_FreeTexture(r->colortexture[j]);
4681                         if (r->depthtexture)
4682                                 R_FreeTexture(r->depthtexture);
4683                         Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4684                 }
4685         }
4686 }
4687
4688 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4689 {
4690         float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4691         x1 = x * iw;
4692         x2 = (x + w) * iw;
4693         y1 = (th - y) * ih;
4694         y2 = (th - y - h) * ih;
4695         texcoord2f[0] = x1;
4696         texcoord2f[2] = x2;
4697         texcoord2f[4] = x2;
4698         texcoord2f[6] = x1;
4699         texcoord2f[1] = y1;
4700         texcoord2f[3] = y1;
4701         texcoord2f[5] = y2;
4702         texcoord2f[7] = y2;
4703 }
4704
4705 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)
4706 {
4707         int i, j, end;
4708         r_rendertarget_t *r = NULL;
4709         char vabuf[256];
4710         // first try to reuse an existing slot if possible
4711         end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
4712         for (i = 0; i < end; i++)
4713         {
4714                 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4715                 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)
4716                         break;
4717         }
4718         if (i == end)
4719         {
4720                 // no unused exact match found, so we have to make one in the first unused slot
4721                 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4722                 r->texturewidth = texturewidth;
4723                 r->textureheight = textureheight;
4724                 r->colortextype[0] = colortextype0;
4725                 r->colortextype[1] = colortextype1;
4726                 r->colortextype[2] = colortextype2;
4727                 r->colortextype[3] = colortextype3;
4728                 r->depthtextype = depthtextype;
4729                 r->depthisrenderbuffer = depthisrenderbuffer;
4730                 for (j = 0; j < 4; j++)
4731                         if (r->colortextype[j])
4732                                 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);
4733                 if (r->depthtextype)
4734                 {
4735                         if (r->depthisrenderbuffer)
4736                                 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);
4737                         else
4738                                 r->depthtexture = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "rendertarget%i_depth_type%i", i, j, (int)r->depthtextype), r->texturewidth, r->textureheight, NULL, r->depthtextype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
4739                 }
4740                 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4741         }
4742         r_refdef.stats[r_stat_rendertargets_used]++;
4743         r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4744         r->lastusetime = realtime;
4745         R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4746         return r;
4747 }
4748
4749 static void R_Water_StartFrame(void)
4750 {
4751         int waterwidth, waterheight;
4752
4753         if (vid.width > (int)vid.maxtexturesize_2d || vid.height > (int)vid.maxtexturesize_2d)
4754                 return;
4755
4756         // set waterwidth and waterheight to the water resolution that will be
4757         // used (often less than the screen resolution for faster rendering)
4758         waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width);
4759         waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height);
4760         R_GetScaledViewSize(waterwidth, waterheight, &waterwidth, &waterheight);
4761
4762         if (!r_water.integer || r_showsurfaces.integer)
4763                 waterwidth = waterheight = 0;
4764
4765         // set up variables that will be used in shader setup
4766         r_fb.water.waterwidth = waterwidth;
4767         r_fb.water.waterheight = waterheight;
4768         r_fb.water.texturewidth = waterwidth;
4769         r_fb.water.textureheight = waterheight;
4770         r_fb.water.camerawidth = waterwidth;
4771         r_fb.water.cameraheight = waterheight;
4772         r_fb.water.screenscale[0] = 0.5f;
4773         r_fb.water.screenscale[1] = 0.5f;
4774         r_fb.water.screencenter[0] = 0.5f;
4775         r_fb.water.screencenter[1] = 0.5f;
4776         r_fb.water.enabled = waterwidth != 0;
4777
4778         r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4779         r_fb.water.numwaterplanes = 0;
4780 }
4781
4782 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4783 {
4784         int planeindex, bestplaneindex, vertexindex;
4785         vec3_t mins, maxs, normal, center, v, n;
4786         vec_t planescore, bestplanescore;
4787         mplane_t plane;
4788         r_waterstate_waterplane_t *p;
4789         texture_t *t = R_GetCurrentTexture(surface->texture);
4790
4791         rsurface.texture = t;
4792         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4793         // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4794         if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4795                 return;
4796         // average the vertex normals, find the surface bounds (after deformvertexes)
4797         Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4798         Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4799         VectorCopy(n, normal);
4800         VectorCopy(v, mins);
4801         VectorCopy(v, maxs);
4802         for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4803         {
4804                 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4805                 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4806                 VectorAdd(normal, n, normal);
4807                 mins[0] = min(mins[0], v[0]);
4808                 mins[1] = min(mins[1], v[1]);
4809                 mins[2] = min(mins[2], v[2]);
4810                 maxs[0] = max(maxs[0], v[0]);
4811                 maxs[1] = max(maxs[1], v[1]);
4812                 maxs[2] = max(maxs[2], v[2]);
4813         }
4814         VectorNormalize(normal);
4815         VectorMAM(0.5f, mins, 0.5f, maxs, center);
4816
4817         VectorCopy(normal, plane.normal);
4818         VectorNormalize(plane.normal);
4819         plane.dist = DotProduct(center, plane.normal);
4820         PlaneClassify(&plane);
4821         if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4822         {
4823                 // skip backfaces (except if nocullface is set)
4824 //              if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4825 //                      return;
4826                 VectorNegate(plane.normal, plane.normal);
4827                 plane.dist *= -1;
4828                 PlaneClassify(&plane);
4829         }
4830
4831
4832         // find a matching plane if there is one
4833         bestplaneindex = -1;
4834         bestplanescore = 1048576.0f;
4835         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4836         {
4837                 if(p->camera_entity == t->camera_entity)
4838                 {
4839                         planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4840                         if (bestplaneindex < 0 || bestplanescore > planescore)
4841                         {
4842                                 bestplaneindex = planeindex;
4843                                 bestplanescore = planescore;
4844                         }
4845                 }
4846         }
4847         planeindex = bestplaneindex;
4848
4849         // if this surface does not fit any known plane rendered this frame, add one
4850         if (planeindex < 0 || bestplanescore > 0.001f)
4851         {
4852                 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4853                 {
4854                         // store the new plane
4855                         planeindex = r_fb.water.numwaterplanes++;
4856                         p = r_fb.water.waterplanes + planeindex;
4857                         p->plane = plane;
4858                         // clear materialflags and pvs
4859                         p->materialflags = 0;
4860                         p->pvsvalid = false;
4861                         p->camera_entity = t->camera_entity;
4862                         VectorCopy(mins, p->mins);
4863                         VectorCopy(maxs, p->maxs);
4864                 }
4865                 else
4866                 {
4867                         // We're totally screwed.
4868                         return;
4869                 }
4870         }
4871         else
4872         {
4873                 // merge mins/maxs when we're adding this surface to the plane
4874                 p = r_fb.water.waterplanes + planeindex;
4875                 p->mins[0] = min(p->mins[0], mins[0]);
4876                 p->mins[1] = min(p->mins[1], mins[1]);
4877                 p->mins[2] = min(p->mins[2], mins[2]);
4878                 p->maxs[0] = max(p->maxs[0], maxs[0]);
4879                 p->maxs[1] = max(p->maxs[1], maxs[1]);
4880                 p->maxs[2] = max(p->maxs[2], maxs[2]);
4881         }
4882         // merge this surface's materialflags into the waterplane
4883         p->materialflags |= t->currentmaterialflags;
4884         if(!(p->materialflags & MATERIALFLAG_CAMERA))
4885         {
4886                 // merge this surface's PVS into the waterplane
4887                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4888                  && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4889                 {
4890                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4891                         p->pvsvalid = true;
4892                 }
4893         }
4894 }
4895
4896 extern cvar_t r_drawparticles;
4897 extern cvar_t r_drawdecals;
4898
4899 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4900 {
4901         int myscissor[4];
4902         r_refdef_view_t originalview;
4903         r_refdef_view_t myview;
4904         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;
4905         r_waterstate_waterplane_t *p;
4906         vec3_t visorigin;
4907         r_rendertarget_t *rt;
4908
4909         originalview = r_refdef.view;
4910
4911         // lowquality hack, temporarily shut down some cvars and restore afterwards
4912         qualityreduction = r_water_lowquality.integer;
4913         if (qualityreduction > 0)
4914         {
4915                 if (qualityreduction >= 1)
4916                 {
4917                         old_r_shadows = r_shadows.integer;
4918                         old_r_worldrtlight = r_shadow_realtime_world.integer;
4919                         old_r_dlight = r_shadow_realtime_dlight.integer;
4920                         Cvar_SetValueQuick(&r_shadows, 0);
4921                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4922                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4923                 }
4924                 if (qualityreduction >= 2)
4925                 {
4926                         old_r_dynamic = r_dynamic.integer;
4927                         old_r_particles = r_drawparticles.integer;
4928                         old_r_decals = r_drawdecals.integer;
4929                         Cvar_SetValueQuick(&r_dynamic, 0);
4930                         Cvar_SetValueQuick(&r_drawparticles, 0);
4931                         Cvar_SetValueQuick(&r_drawdecals, 0);
4932                 }
4933         }
4934
4935         for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4936         {
4937                 p->rt_reflection = NULL;
4938                 p->rt_refraction = NULL;
4939                 p->rt_camera = NULL;
4940         }
4941
4942         // render views
4943         r_refdef.view = originalview;
4944         r_refdef.view.showdebug = false;
4945         r_refdef.view.width = r_fb.water.waterwidth;
4946         r_refdef.view.height = r_fb.water.waterheight;
4947         r_refdef.view.useclipplane = true;
4948         myview = r_refdef.view;
4949         r_fb.water.renderingscene = true;
4950         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4951         {
4952                 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4953                         continue;
4954
4955                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4956                 {
4957                         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);
4958                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4959                                 goto error;
4960                         r_refdef.view = myview;
4961                         Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4962                         Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4963                         if(r_water_scissormode.integer)
4964                         {
4965                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4966                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4967                                 {
4968                                         p->rt_reflection = NULL;
4969                                         p->rt_refraction = NULL;
4970                                         p->rt_camera = NULL;
4971                                         continue;
4972                                 }
4973                         }
4974
4975                         r_refdef.view.clipplane = p->plane;
4976                         // reflected view origin may be in solid, so don't cull with it
4977                         r_refdef.view.usevieworiginculling = false;
4978                         // reverse the cullface settings for this render
4979                         r_refdef.view.cullface_front = GL_FRONT;
4980                         r_refdef.view.cullface_back = GL_BACK;
4981                         // combined pvs (based on what can be seen from each surface center)
4982                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4983                         {
4984                                 r_refdef.view.usecustompvs = true;
4985                                 if (p->pvsvalid)
4986                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4987                                 else
4988                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4989                         }
4990
4991                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4992                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4993                         GL_ScissorTest(false);
4994                         R_ClearScreen(r_refdef.fogenabled);
4995                         GL_ScissorTest(true);
4996                         if(r_water_scissormode.integer & 2)
4997                                 R_View_UpdateWithScissor(myscissor);
4998                         else
4999                                 R_View_Update();
5000                         R_AnimCache_CacheVisibleEntities();
5001                         if(r_water_scissormode.integer & 1)
5002                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
5003                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5004
5005                         r_fb.water.hideplayer = false;
5006                         p->rt_reflection = rt;
5007                 }
5008
5009                 // render the normal view scene and copy into texture
5010                 // (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)
5011                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
5012                 {
5013                         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);
5014                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5015                                 goto error;
5016                         r_refdef.view = myview;
5017                         if(r_water_scissormode.integer)
5018                         {
5019                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
5020                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
5021                                 {
5022                                         p->rt_reflection = NULL;
5023                                         p->rt_refraction = NULL;
5024                                         p->rt_camera = NULL;
5025                                         continue;
5026                                 }
5027                         }
5028
5029                         // combined pvs (based on what can be seen from each surface center)
5030                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
5031                         {
5032                                 r_refdef.view.usecustompvs = true;
5033                                 if (p->pvsvalid)
5034                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
5035                                 else
5036                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
5037                         }
5038
5039                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
5040
5041                         r_refdef.view.clipplane = p->plane;
5042                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5043                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5044
5045                         if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
5046                         {
5047                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5048                                 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
5049                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5050                                 R_RenderView_UpdateViewVectors();
5051                                 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5052                                 {
5053                                         r_refdef.view.usecustompvs = true;
5054                                         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);
5055                                 }
5056                         }
5057
5058                         PlaneClassify(&r_refdef.view.clipplane);
5059
5060                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5061                         GL_ScissorTest(false);
5062                         R_ClearScreen(r_refdef.fogenabled);
5063                         GL_ScissorTest(true);
5064                         if(r_water_scissormode.integer & 2)
5065                                 R_View_UpdateWithScissor(myscissor);
5066                         else
5067                                 R_View_Update();
5068                         R_AnimCache_CacheVisibleEntities();
5069                         if(r_water_scissormode.integer & 1)
5070                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
5071                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5072
5073                         r_fb.water.hideplayer = false;
5074                         p->rt_refraction = rt;
5075                 }
5076                 else if (p->materialflags & MATERIALFLAG_CAMERA)
5077                 {
5078                         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);
5079                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5080                                 goto error;
5081                         r_refdef.view = myview;
5082
5083                         r_refdef.view.clipplane = p->plane;
5084                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5085                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5086
5087                         r_refdef.view.width = r_fb.water.camerawidth;
5088                         r_refdef.view.height = r_fb.water.cameraheight;
5089                         r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
5090                         r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
5091                         r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
5092                         r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
5093
5094                         if(p->camera_entity)
5095                         {
5096                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5097                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5098                         }
5099
5100                         // note: all of the view is used for displaying... so
5101                         // there is no use in scissoring
5102
5103                         // reverse the cullface settings for this render
5104                         r_refdef.view.cullface_front = GL_FRONT;
5105                         r_refdef.view.cullface_back = GL_BACK;
5106                         // also reverse the view matrix
5107                         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
5108                         R_RenderView_UpdateViewVectors();
5109                         if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5110                         {
5111                                 r_refdef.view.usecustompvs = true;
5112                                 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);
5113                         }
5114                         
5115                         // camera needs no clipplane
5116                         r_refdef.view.useclipplane = false;
5117                         // TODO: is the camera origin always valid?  if so we don't need to clear this
5118                         r_refdef.view.usevieworiginculling = false;
5119
5120                         PlaneClassify(&r_refdef.view.clipplane);
5121
5122                         r_fb.water.hideplayer = false;
5123
5124                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5125                         GL_ScissorTest(false);
5126                         R_ClearScreen(r_refdef.fogenabled);
5127                         GL_ScissorTest(true);
5128                         R_View_Update();
5129                         R_AnimCache_CacheVisibleEntities();
5130                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5131
5132                         r_fb.water.hideplayer = false;
5133                         p->rt_camera = rt;
5134                 }
5135
5136         }
5137         r_fb.water.renderingscene = false;
5138         r_refdef.view = originalview;
5139         R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5140         R_View_Update();
5141         R_AnimCache_CacheVisibleEntities();
5142         goto finish;
5143 error:
5144         r_refdef.view = originalview;
5145         r_fb.water.renderingscene = false;
5146         Cvar_SetValueQuick(&r_water, 0);
5147         Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed!  Turned off r_water.\n");
5148 finish:
5149         // lowquality hack, restore cvars
5150         if (qualityreduction > 0)
5151         {
5152                 if (qualityreduction >= 1)
5153                 {
5154                         Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5155                         Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5156                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5157                 }
5158                 if (qualityreduction >= 2)
5159                 {
5160                         Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5161                         Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5162                         Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5163                 }
5164         }
5165 }
5166
5167 static void R_Bloom_StartFrame(void)
5168 {
5169         int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
5170         int viewwidth, viewheight;
5171         textype_t textype = TEXTYPE_COLORBUFFER;
5172
5173         // clear the pointers to rendertargets from last frame as they're stale
5174         r_fb.rt_screen = NULL;
5175         r_fb.rt_bloom = NULL;
5176
5177         switch (vid.renderpath)
5178         {
5179         case RENDERPATH_GL20:
5180                 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5181                 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5182                 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5183                 // for simplicity, bloom requires FBO render to texture, which basically all video drivers support now
5184                 if (!vid.support.ext_framebuffer_object)
5185                         return;
5186                 break;
5187         case RENDERPATH_GLES2:
5188                 r_fb.usedepthtextures = false;
5189                 break;
5190         }
5191
5192         if (r_viewscale_fpsscaling.integer)
5193         {
5194                 double actualframetime;
5195                 double targetframetime;
5196                 double adjust;
5197                 actualframetime = r_refdef.lastdrawscreentime;
5198                 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5199                 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5200                 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5201                 if (r_viewscale_fpsscaling_stepsize.value > 0)
5202                         adjust = (int)(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5203                 viewscalefpsadjusted += adjust;
5204                 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5205         }
5206         else
5207                 viewscalefpsadjusted = 1.0f;
5208
5209         R_GetScaledViewSize(r_refdef.view.width, r_refdef.view.height, &viewwidth, &viewheight);
5210
5211         // set bloomwidth and bloomheight to the bloom resolution that will be
5212         // used (often less than the screen resolution for faster rendering)
5213         r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, vid.width);
5214         r_fb.bloomheight = r_fb.bloomwidth * vid.height / vid.width;
5215         r_fb.bloomheight = bound(1, r_fb.bloomheight, vid.height);
5216         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5217         r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5218
5219         // calculate desired texture sizes
5220         screentexturewidth = viewwidth;
5221         screentextureheight = viewheight;
5222         bloomtexturewidth = r_fb.bloomwidth;
5223         bloomtextureheight = r_fb.bloomheight;
5224
5225         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))
5226         {
5227                 Cvar_SetValueQuick(&r_bloom, 0);
5228                 Cvar_SetValueQuick(&r_motionblur, 0);
5229                 Cvar_SetValueQuick(&r_damageblur, 0);
5230         }
5231
5232         // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5233         if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5234         {
5235                 if (r_fb.ghosttexture)
5236                         R_FreeTexture(r_fb.ghosttexture);
5237                 r_fb.ghosttexture = NULL;
5238
5239                 r_fb.screentexturewidth = screentexturewidth;
5240                 r_fb.screentextureheight = screentextureheight;
5241                 r_fb.textype = textype;
5242
5243                 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5244                 {
5245                         if (r_motionblur.value > 0 || r_damageblur.value > 0)
5246                                 r_fb.ghosttexture = R_LoadTexture2D(r_main_texturepool, "framebuffermotionblur", r_fb.screentexturewidth, r_fb.screentextureheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
5247                         r_fb.ghosttexture_valid = false;
5248                 }
5249         }
5250
5251         if (r_bloom.integer)
5252         {
5253                 // bloom texture is a different resolution
5254                 r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.width);
5255                 r_fb.bloomheight = r_fb.bloomwidth * r_refdef.view.height / r_refdef.view.width;
5256                 r_fb.bloomheight = bound(1, r_fb.bloomheight, r_refdef.view.height);
5257         }
5258         else
5259                 r_fb.bloomwidth = r_fb.bloomheight = 0;
5260
5261         r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5262
5263         r_refdef.view.clear = true;
5264 }
5265
5266 static void R_Bloom_MakeTexture(void)
5267 {
5268         int x, range, dir;
5269         float xoffset, yoffset, r, brighten;
5270         float colorscale = r_bloom_colorscale.value;
5271         r_viewport_t bloomviewport;
5272         r_rendertarget_t *prev, *cur;
5273         textype_t textype = r_fb.rt_screen->colortextype[0];
5274
5275         r_refdef.stats[r_stat_bloom]++;
5276
5277         R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5278
5279         // scale down screen texture to the bloom texture size
5280         CHECKGLERROR
5281         prev = r_fb.rt_screen;
5282         cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5283         R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5284         R_SetViewport(&bloomviewport);
5285         GL_CullFace(GL_NONE);
5286         GL_DepthTest(false);
5287         GL_BlendFunc(GL_ONE, GL_ZERO);
5288         GL_Color(colorscale, colorscale, colorscale, 1);
5289         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5290         // TODO: do boxfilter scale-down in shader?
5291         R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, true);
5292         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5293         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5294         // we now have a properly scaled bloom image
5295
5296         // multiply bloom image by itself as many times as desired to darken it
5297         // TODO: if people actually use this it could be done more quickly in the previous shader pass
5298         for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5299         {
5300                 prev = cur;
5301                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5302                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5303                 x *= 2;
5304                 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5305                 if(x <= 2)
5306                         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0);
5307                 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5308                 GL_Color(1,1,1,1); // no fix factor supported here
5309                 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5310                 R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, false);
5311                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5312                 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5313         }
5314
5315         range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5316         brighten = r_bloom_brighten.value;
5317         brighten = sqrt(brighten);
5318         if(range >= 1)
5319                 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5320
5321         for (dir = 0;dir < 2;dir++)
5322         {
5323                 prev = cur;
5324                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5325                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5326                 // blend on at multiple vertical offsets to achieve a vertical blur
5327                 // TODO: do offset blends using GLSL
5328                 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5329                 GL_BlendFunc(GL_ONE, GL_ZERO);
5330                 R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, false);
5331                 for (x = -range;x <= range;x++)
5332                 {
5333                         if (!dir){xoffset = 0;yoffset = x;}
5334                         else {xoffset = x;yoffset = 0;}
5335                         xoffset /= (float)prev->texturewidth;
5336                         yoffset /= (float)prev->textureheight;
5337                         // compute a texcoord array with the specified x and y offset
5338                         r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5339                         r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5340                         r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5341                         r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5342                         r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5343                         r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5344                         r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5345                         r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5346                         // this r value looks like a 'dot' particle, fading sharply to
5347                         // black at the edges
5348                         // (probably not realistic but looks good enough)
5349                         //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5350                         //r = brighten/(range*2+1);
5351                         r = brighten / (range * 2 + 1);
5352                         if(range >= 1)
5353                                 r *= (1 - x*x/(float)((range+1)*(range+1)));
5354                         if (r <= 0)
5355                                 continue;
5356                         GL_Color(r, r, r, 1);
5357                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5358                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5359                         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5360                         GL_BlendFunc(GL_ONE, GL_ONE);
5361                 }
5362         }
5363
5364         // now we have the bloom image, so keep track of it
5365         r_fb.rt_bloom = cur;
5366 }
5367
5368 static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5369 {
5370         dpuint64 permutation;
5371         float uservecs[4][4];
5372         rtexture_t *viewtexture;
5373         rtexture_t *bloomtexture;
5374
5375         R_EntityMatrix(&identitymatrix);
5376
5377         if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
5378         {
5379                 // declare variables
5380                 float blur_factor, blur_mouseaccel, blur_velocity;
5381                 static float blur_average; 
5382                 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5383
5384                 // set a goal for the factoring
5385                 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value) 
5386                         / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5387                 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value) 
5388                         / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5389                 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value) 
5390                         + (blur_mouseaccel * r_motionblur_mousefactor.value));
5391
5392                 // from the goal, pick an averaged value between goal and last value
5393                 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5394                 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5395
5396                 // enforce minimum amount of blur 
5397                 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5398
5399                 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5400
5401                 // calculate values into a standard alpha
5402                 cl.motionbluralpha = 1 - exp(-
5403                                 (
5404                                         (r_motionblur.value * blur_factor / 80)
5405                                         +
5406                                         (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5407                                 )
5408                                 /
5409                                 max(0.0001, cl.time - cl.oldtime) // fps independent
5410                                 );
5411
5412                 // randomization for the blur value to combat persistent ghosting
5413                 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5414                 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5415
5416                 // apply the blur
5417                 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5418                 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5419                 {
5420                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5421                         GL_Color(1, 1, 1, cl.motionbluralpha);
5422                         R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5423                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5424                         R_SetupShader_Generic(r_fb.ghosttexture, NULL, GL_MODULATE, 1, false, true, true);
5425                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5426                         r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5427                 }
5428
5429                 // updates old view angles for next pass
5430                 VectorCopy(cl.viewangles, blur_oldangles);
5431
5432                 // copy view into the ghost texture
5433                 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5434                 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5435                 r_fb.ghosttexture_valid = true;
5436         }
5437
5438         if (r_fb.bloomwidth)
5439         {
5440                 // make the bloom texture
5441                 R_Bloom_MakeTexture();
5442         }
5443
5444 #if _MSC_VER >= 1400
5445 #define sscanf sscanf_s
5446 #endif
5447         memset(uservecs, 0, sizeof(uservecs));
5448         if (r_glsl_postprocess_uservec1_enable.integer)
5449                 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5450         if (r_glsl_postprocess_uservec2_enable.integer)
5451                 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5452         if (r_glsl_postprocess_uservec3_enable.integer)
5453                 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5454         if (r_glsl_postprocess_uservec4_enable.integer)
5455                 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5456
5457         // render to the screen fbo
5458         R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5459         GL_Color(1, 1, 1, 1);
5460         GL_BlendFunc(GL_ONE, GL_ZERO);
5461
5462         viewtexture = r_fb.rt_screen->colortexture[0];
5463         bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5464
5465         if (r_rendertarget_debug.integer >= 0)
5466         {
5467                 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5468                 if (rt && rt->colortexture[0])
5469                 {
5470                         viewtexture = rt->colortexture[0];
5471                         bloomtexture = NULL;
5472                 }
5473         }
5474
5475         R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5476         switch(vid.renderpath)
5477         {
5478         case RENDERPATH_GL20:
5479         case RENDERPATH_GLES2:
5480                 permutation =
5481                         (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5482                         | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5483                         | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5484                         | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5485                         | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5486                 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5487                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First     , viewtexture);
5488                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second    , bloomtexture);
5489                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps       );
5490                 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]);
5491                 if (r_glsl_permutation->loc_PixelSize               >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize         , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5492                 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]);
5493                 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]);
5494                 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]);
5495                 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]);
5496                 if (r_glsl_permutation->loc_Saturation              >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation        , r_glsl_saturation.value);
5497                 if (r_glsl_permutation->loc_PixelToScreenTexCoord   >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
5498                 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);
5499                 break;
5500         }
5501         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5502         r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5503 }
5504
5505 matrix4x4_t r_waterscrollmatrix;
5506
5507 void R_UpdateFog(void)
5508 {
5509         // Nehahra fog
5510         if (gamemode == GAME_NEHAHRA)
5511         {
5512                 if (gl_fogenable.integer)
5513                 {
5514                         r_refdef.oldgl_fogenable = true;
5515                         r_refdef.fog_density = gl_fogdensity.value;
5516                         r_refdef.fog_red = gl_fogred.value;
5517                         r_refdef.fog_green = gl_foggreen.value;
5518                         r_refdef.fog_blue = gl_fogblue.value;
5519                         r_refdef.fog_alpha = 1;
5520                         r_refdef.fog_start = 0;
5521                         r_refdef.fog_end = gl_skyclip.value;
5522                         r_refdef.fog_height = 1<<30;
5523                         r_refdef.fog_fadedepth = 128;
5524                 }
5525                 else if (r_refdef.oldgl_fogenable)
5526                 {
5527                         r_refdef.oldgl_fogenable = false;
5528                         r_refdef.fog_density = 0;
5529                         r_refdef.fog_red = 0;
5530                         r_refdef.fog_green = 0;
5531                         r_refdef.fog_blue = 0;
5532                         r_refdef.fog_alpha = 0;
5533                         r_refdef.fog_start = 0;
5534                         r_refdef.fog_end = 0;
5535                         r_refdef.fog_height = 1<<30;
5536                         r_refdef.fog_fadedepth = 128;
5537                 }
5538         }
5539
5540         // fog parms
5541         r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5542         r_refdef.fog_start = max(0, r_refdef.fog_start);
5543         r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5544
5545         if (r_refdef.fog_density && r_drawfog.integer)
5546         {
5547                 r_refdef.fogenabled = true;
5548                 // this is the point where the fog reaches 0.9986 alpha, which we
5549                 // consider a good enough cutoff point for the texture
5550                 // (0.9986 * 256 == 255.6)
5551                 if (r_fog_exp2.integer)
5552                         r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5553                 else
5554                         r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5555                 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5556                 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5557                 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5558                 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5559                         R_BuildFogHeightTexture();
5560                 // fog color was already set
5561                 // update the fog texture
5562                 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)
5563                         R_BuildFogTexture();
5564                 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5565                 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5566         }
5567         else
5568                 r_refdef.fogenabled = false;
5569
5570         // fog color
5571         if (r_refdef.fog_density)
5572         {
5573                 r_refdef.fogcolor[0] = r_refdef.fog_red;
5574                 r_refdef.fogcolor[1] = r_refdef.fog_green;
5575                 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5576
5577                 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5578                 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5579                 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5580                 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5581
5582                 {
5583                         vec3_t fogvec;
5584                         VectorCopy(r_refdef.fogcolor, fogvec);
5585                         //   color.rgb *= ContrastBoost * SceneBrightness;
5586                         VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5587                         r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5588                         r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5589                         r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5590                 }
5591         }
5592 }
5593
5594 void R_UpdateVariables(void)
5595 {
5596         R_Textures_Frame();
5597
5598         r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5599
5600         r_refdef.farclip = r_farclip_base.value;
5601         if (r_refdef.scene.worldmodel)
5602                 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5603         r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5604
5605         if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5606                 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5607         r_refdef.polygonfactor = 0;
5608         r_refdef.polygonoffset = 0;
5609
5610         r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5611         r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5612         r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5613         r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5614         r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5615         if (FAKELIGHT_ENABLED)
5616         {
5617                 r_refdef.scene.lightmapintensity *= r_fakelight_intensity.value;
5618         }
5619         else if (r_refdef.scene.worldmodel)
5620         {
5621                 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5622         }
5623         if (r_showsurfaces.integer)
5624         {
5625                 r_refdef.scene.rtworld = false;
5626                 r_refdef.scene.rtworldshadows = false;
5627                 r_refdef.scene.rtdlight = false;
5628                 r_refdef.scene.rtdlightshadows = false;
5629                 r_refdef.scene.lightmapintensity = 0;
5630         }
5631
5632         r_gpuskeletal = false;
5633         switch(vid.renderpath)
5634         {
5635         case RENDERPATH_GL20:
5636                 r_gpuskeletal = vid.support.arb_uniform_buffer_object && r_glsl_skeletal.integer && !r_showsurfaces.integer; // FIXME add r_showsurfaces support to GLSL skeletal!
5637         case RENDERPATH_GLES2:
5638                 if(!vid_gammatables_trivial)
5639                 {
5640                         if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5641                         {
5642                                 // build GLSL gamma texture
5643 #define RAMPWIDTH 256
5644                                 unsigned short ramp[RAMPWIDTH * 3];
5645                                 unsigned char rampbgr[RAMPWIDTH][4];
5646                                 int i;
5647
5648                                 r_texture_gammaramps_serial = vid_gammatables_serial;
5649
5650                                 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5651                                 for(i = 0; i < RAMPWIDTH; ++i)
5652                                 {
5653                                         rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5654                                         rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5655                                         rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5656                                         rampbgr[i][3] = 0;
5657                                 }
5658                                 if (r_texture_gammaramps)
5659                                 {
5660                                         R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1);
5661                                 }
5662                                 else
5663                                 {
5664                                         r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5665                                 }
5666                         }
5667                 }
5668                 else
5669                 {
5670                         // remove GLSL gamma texture
5671                 }
5672                 break;
5673         }
5674 }
5675
5676 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5677 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5678 /*
5679 ================
5680 R_SelectScene
5681 ================
5682 */
5683 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5684         if( scenetype != r_currentscenetype ) {
5685                 // store the old scenetype
5686                 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5687                 r_currentscenetype = scenetype;
5688                 // move in the new scene
5689                 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5690         }
5691 }
5692
5693 /*
5694 ================
5695 R_GetScenePointer
5696 ================
5697 */
5698 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5699 {
5700         // of course, we could also add a qboolean that provides a lock state and a ReleaseScenePointer function..
5701         if( scenetype == r_currentscenetype ) {
5702                 return &r_refdef.scene;
5703         } else {
5704                 return &r_scenes_store[ scenetype ];
5705         }
5706 }
5707
5708 static int R_SortEntities_Compare(const void *ap, const void *bp)
5709 {
5710         const entity_render_t *a = *(const entity_render_t **)ap;
5711         const entity_render_t *b = *(const entity_render_t **)bp;
5712
5713         // 1. compare model
5714         if(a->model < b->model)
5715                 return -1;
5716         if(a->model > b->model)
5717                 return +1;
5718
5719         // 2. compare skin
5720         // TODO possibly calculate the REAL skinnum here first using
5721         // skinscenes?
5722         if(a->skinnum < b->skinnum)
5723                 return -1;
5724         if(a->skinnum > b->skinnum)
5725                 return +1;
5726
5727         // everything we compared is equal
5728         return 0;
5729 }
5730 static void R_SortEntities(void)
5731 {
5732         // below or equal 2 ents, sorting never gains anything
5733         if(r_refdef.scene.numentities <= 2)
5734                 return;
5735         // sort
5736         qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5737 }
5738
5739 /*
5740 ================
5741 R_RenderView
5742 ================
5743 */
5744 extern cvar_t r_shadow_bouncegrid;
5745 extern cvar_t v_isometric;
5746 extern void V_MakeViewIsometric(void);
5747 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5748 {
5749         matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5750         int viewfbo = 0;
5751         rtexture_t *viewdepthtexture = NULL;
5752         rtexture_t *viewcolortexture = NULL;
5753         int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5754
5755         // finish any 2D rendering that was queued
5756         DrawQ_Finish();
5757
5758         if (r_timereport_active)
5759                 R_TimeReport("start");
5760         r_textureframe++; // used only by R_GetCurrentTexture
5761         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5762
5763         if(R_CompileShader_CheckStaticParms())
5764                 R_GLSL_Restart_f();
5765
5766         if (!r_drawentities.integer)
5767                 r_refdef.scene.numentities = 0;
5768         else if (r_sortentities.integer)
5769                 R_SortEntities();
5770
5771         R_AnimCache_ClearCache();
5772
5773         /* adjust for stereo display */
5774         if(R_Stereo_Active())
5775         {
5776                 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);
5777                 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5778         }
5779
5780         if (r_refdef.view.isoverlay)
5781         {
5782                 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5783                 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5784                 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5785                 R_TimeReport("depthclear");
5786
5787                 r_refdef.view.showdebug = false;
5788
5789                 r_fb.water.enabled = false;
5790                 r_fb.water.numwaterplanes = 0;
5791
5792                 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5793
5794                 r_refdef.view.matrix = originalmatrix;
5795
5796                 CHECKGLERROR
5797                 return;
5798         }
5799
5800         if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5801         {
5802                 r_refdef.view.matrix = originalmatrix;
5803                 return;
5804         }
5805
5806         r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5807         if (v_isometric.integer && r_refdef.view.ismain)
5808                 V_MakeViewIsometric();
5809
5810         r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5811
5812         if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5813                 // in sRGB fallback, behave similar to true sRGB: convert this
5814                 // value from linear to sRGB
5815                 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5816
5817         R_RenderView_UpdateViewVectors();
5818
5819         R_Shadow_UpdateWorldLightSelection();
5820
5821         // this will set up r_fb.rt_screen
5822         R_Bloom_StartFrame();
5823
5824         // apply bloom brightness offset
5825         if(r_fb.rt_bloom)
5826                 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5827
5828         // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5829         if (r_fb.rt_screen)
5830         {
5831                 viewfbo = r_fb.rt_screen->fbo;
5832                 viewdepthtexture = r_fb.rt_screen->depthtexture;
5833                 viewcolortexture = r_fb.rt_screen->colortexture[0];
5834                 viewx = 0;
5835                 viewy = 0;
5836                 viewwidth = width;
5837                 viewheight = height;
5838         }
5839
5840         R_Water_StartFrame();
5841
5842         CHECKGLERROR
5843         if (r_timereport_active)
5844                 R_TimeReport("viewsetup");
5845
5846         R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5847
5848         // clear the whole fbo every frame - otherwise the driver will consider
5849         // it to be an inter-frame texture and stall in multi-gpu configurations
5850         if (r_fb.rt_screen)
5851                 GL_ScissorTest(false);
5852         R_ClearScreen(r_refdef.fogenabled);
5853         if (r_timereport_active)
5854                 R_TimeReport("viewclear");
5855
5856         r_refdef.view.clear = true;
5857
5858         r_refdef.view.showdebug = true;
5859
5860         R_View_Update();
5861         if (r_timereport_active)
5862                 R_TimeReport("visibility");
5863
5864         R_AnimCache_CacheVisibleEntities();
5865         if (r_timereport_active)
5866                 R_TimeReport("animcache");
5867
5868         R_Shadow_UpdateBounceGridTexture();
5869         if (r_timereport_active && r_shadow_bouncegrid.integer)
5870                 R_TimeReport("bouncegrid");
5871
5872         r_fb.water.numwaterplanes = 0;
5873         if (r_fb.water.enabled)
5874                 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5875
5876         // for the actual view render we use scissoring a fair amount, so scissor
5877         // test needs to be on
5878         if (r_fb.rt_screen)
5879                 GL_ScissorTest(true);
5880         GL_Scissor(viewx, viewy, viewwidth, viewheight);
5881         R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5882         r_fb.water.numwaterplanes = 0;
5883
5884         // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5885         GL_ScissorTest(false);
5886
5887         R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
5888         if (r_timereport_active)
5889                 R_TimeReport("blendview");
5890
5891         r_refdef.view.matrix = originalmatrix;
5892
5893         CHECKGLERROR
5894
5895         // go back to 2d rendering
5896         DrawQ_Start();
5897 }
5898
5899 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5900 {
5901         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5902         {
5903                 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5904                 if (r_timereport_active)
5905                         R_TimeReport("waterworld");
5906         }
5907
5908         // don't let sound skip if going slow
5909         if (r_refdef.scene.extraupdate)
5910                 S_ExtraUpdate ();
5911
5912         R_DrawModelsAddWaterPlanes();
5913         if (r_timereport_active)
5914                 R_TimeReport("watermodels");
5915
5916         if (r_fb.water.numwaterplanes)
5917         {
5918                 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5919                 if (r_timereport_active)
5920                         R_TimeReport("waterscenes");
5921         }
5922 }
5923
5924 extern cvar_t cl_locs_show;
5925 static void R_DrawLocs(void);
5926 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5927 static void R_DrawModelDecals(void);
5928 extern cvar_t cl_decals_newsystem;
5929 extern qboolean r_shadow_usingdeferredprepass;
5930 extern int r_shadow_shadowmapatlas_modelshadows_size;
5931 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5932 {
5933         qboolean shadowmapping = false;
5934
5935         if (r_timereport_active)
5936                 R_TimeReport("beginscene");
5937
5938         r_refdef.stats[r_stat_renders]++;
5939
5940         R_UpdateFog();
5941
5942         // don't let sound skip if going slow
5943         if (r_refdef.scene.extraupdate)
5944                 S_ExtraUpdate ();
5945
5946         R_MeshQueue_BeginScene();
5947
5948         R_SkyStartFrame();
5949
5950         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);
5951
5952         if (r_timereport_active)
5953                 R_TimeReport("skystartframe");
5954
5955         if (cl.csqc_vidvars.drawworld)
5956         {
5957                 // don't let sound skip if going slow
5958                 if (r_refdef.scene.extraupdate)
5959                         S_ExtraUpdate ();
5960
5961                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5962                 {
5963                         r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5964                         if (r_timereport_active)
5965                                 R_TimeReport("worldsky");
5966                 }
5967
5968                 if (R_DrawBrushModelsSky() && r_timereport_active)
5969                         R_TimeReport("bmodelsky");
5970
5971                 if (skyrendermasked && skyrenderlater)
5972                 {
5973                         // we have to force off the water clipping plane while rendering sky
5974                         R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5975                         R_Sky();
5976                         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5977                         if (r_timereport_active)
5978                                 R_TimeReport("sky");
5979                 }
5980         }
5981
5982         // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5983         r_shadow_viewfbo = viewfbo;
5984         r_shadow_viewdepthtexture = viewdepthtexture;
5985         r_shadow_viewcolortexture = viewcolortexture;
5986         r_shadow_viewx = viewx;
5987         r_shadow_viewy = viewy;
5988         r_shadow_viewwidth = viewwidth;
5989         r_shadow_viewheight = viewheight;
5990
5991         R_Shadow_PrepareModelShadows();
5992         R_Shadow_PrepareLights();
5993         if (r_timereport_active)
5994                 R_TimeReport("preparelights");
5995
5996         // render all the shadowmaps that will be used for this view
5997         shadowmapping = R_Shadow_ShadowMappingEnabled();
5998         if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
5999         {
6000                 R_Shadow_DrawShadowMaps();
6001                 if (r_timereport_active)
6002                         R_TimeReport("shadowmaps");
6003         }
6004
6005         // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
6006         if (r_shadow_usingdeferredprepass)
6007                 R_Shadow_DrawPrepass();
6008
6009         // now we begin the forward pass of the view render
6010         if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
6011         {
6012                 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
6013                 if (r_timereport_active)
6014                         R_TimeReport("worlddepth");
6015         }
6016         if (r_depthfirst.integer >= 2)
6017         {
6018                 R_DrawModelsDepth();
6019                 if (r_timereport_active)
6020                         R_TimeReport("modeldepth");
6021         }
6022
6023         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
6024         {
6025                 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
6026                 if (r_timereport_active)
6027                         R_TimeReport("world");
6028         }
6029
6030         // don't let sound skip if going slow
6031         if (r_refdef.scene.extraupdate)
6032                 S_ExtraUpdate ();
6033
6034         R_DrawModels();
6035         if (r_timereport_active)
6036                 R_TimeReport("models");
6037
6038         // don't let sound skip if going slow
6039         if (r_refdef.scene.extraupdate)
6040                 S_ExtraUpdate ();
6041
6042         if (!r_shadow_usingdeferredprepass)
6043         {
6044                 R_Shadow_DrawLights();
6045                 if (r_timereport_active)
6046                         R_TimeReport("rtlights");
6047         }
6048
6049         // don't let sound skip if going slow
6050         if (r_refdef.scene.extraupdate)
6051                 S_ExtraUpdate ();
6052
6053         if (cl.csqc_vidvars.drawworld)
6054         {
6055                 if (cl_decals_newsystem.integer)
6056                 {
6057                         R_DrawModelDecals();
6058                         if (r_timereport_active)
6059                                 R_TimeReport("modeldecals");
6060                 }
6061                 else
6062                 {
6063                         R_DrawDecals();
6064                         if (r_timereport_active)
6065                                 R_TimeReport("decals");
6066                 }
6067
6068                 R_DrawParticles();
6069                 if (r_timereport_active)
6070                         R_TimeReport("particles");
6071
6072                 R_DrawExplosions();
6073                 if (r_timereport_active)
6074                         R_TimeReport("explosions");
6075         }
6076
6077         if (r_refdef.view.showdebug)
6078         {
6079                 if (cl_locs_show.integer)
6080                 {
6081                         R_DrawLocs();
6082                         if (r_timereport_active)
6083                                 R_TimeReport("showlocs");
6084                 }
6085
6086                 if (r_drawportals.integer)
6087                 {
6088                         R_DrawPortals();
6089                         if (r_timereport_active)
6090                                 R_TimeReport("portals");
6091                 }
6092
6093                 if (r_showbboxes_client.value > 0)
6094                 {
6095                         R_DrawEntityBBoxes(CLVM_prog);
6096                         if (r_timereport_active)
6097                                 R_TimeReport("clbboxes");
6098                 }
6099                 if (r_showbboxes.value > 0)
6100                 {
6101                         R_DrawEntityBBoxes(SVVM_prog);
6102                         if (r_timereport_active)
6103                                 R_TimeReport("svbboxes");
6104                 }
6105         }
6106
6107         if (r_transparent.integer)
6108         {
6109                 R_MeshQueue_RenderTransparent();
6110                 if (r_timereport_active)
6111                         R_TimeReport("drawtrans");
6112         }
6113
6114         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))
6115         {
6116                 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
6117                 if (r_timereport_active)
6118                         R_TimeReport("worlddebug");
6119                 R_DrawModelsDebug();
6120                 if (r_timereport_active)
6121                         R_TimeReport("modeldebug");
6122         }
6123
6124         if (cl.csqc_vidvars.drawworld)
6125         {
6126                 R_Shadow_DrawCoronas();
6127                 if (r_timereport_active)
6128                         R_TimeReport("coronas");
6129         }
6130
6131         // don't let sound skip if going slow
6132         if (r_refdef.scene.extraupdate)
6133                 S_ExtraUpdate ();
6134 }
6135
6136 static const unsigned short bboxelements[36] =
6137 {
6138         5, 1, 3, 5, 3, 7,
6139         6, 2, 0, 6, 0, 4,
6140         7, 3, 2, 7, 2, 6,
6141         4, 0, 1, 4, 1, 5,
6142         4, 5, 7, 4, 7, 6,
6143         1, 0, 2, 1, 2, 3,
6144 };
6145
6146 #define BBOXEDGES 13
6147 static const float bboxedges[BBOXEDGES][6] = 
6148 {
6149         // whole box
6150         { 0, 0, 0, 1, 1, 1 },
6151         // bottom edges
6152         { 0, 0, 0, 0, 1, 0 },
6153         { 0, 0, 0, 1, 0, 0 },
6154         { 0, 1, 0, 1, 1, 0 },
6155         { 1, 0, 0, 1, 1, 0 },
6156         // top edges
6157         { 0, 0, 1, 0, 1, 1 },
6158         { 0, 0, 1, 1, 0, 1 },
6159         { 0, 1, 1, 1, 1, 1 },
6160         { 1, 0, 1, 1, 1, 1 },
6161         // vertical edges
6162         { 0, 0, 0, 0, 0, 1 },
6163         { 1, 0, 0, 1, 0, 1 },
6164         { 0, 1, 0, 0, 1, 1 },
6165         { 1, 1, 0, 1, 1, 1 },
6166 };
6167
6168 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6169 {
6170         int numvertices = BBOXEDGES * 8;
6171         float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6172         int numtriangles = BBOXEDGES * 12;
6173         unsigned short elements[BBOXEDGES * 36];
6174         int i, edge;
6175         float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6176
6177         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6178
6179         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6180         GL_DepthMask(false);
6181         GL_DepthRange(0, 1);
6182         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6183
6184         for (edge = 0; edge < BBOXEDGES; edge++)
6185         {
6186                 for (i = 0; i < 3; i++)
6187                 {
6188                         edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6189                         edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6190                 }
6191                 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6192                 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6193                 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6194                 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6195                 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6196                 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6197                 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6198                 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6199                 for (i = 0; i < 36; i++)
6200                         elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6201         }
6202         R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6203         if (r_refdef.fogenabled)
6204         {
6205                 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6206                 {
6207                         f1 = RSurf_FogVertex(v);
6208                         f2 = 1 - f1;
6209                         c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6210                         c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6211                         c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6212                 }
6213         }
6214         R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6215         R_Mesh_ResetTextureState();
6216         R_SetupShader_Generic_NoTexture(false, false);
6217         R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6218 }
6219
6220 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6221 {
6222         // hacky overloading of the parameters
6223         prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6224         int i;
6225         float color[4];
6226         prvm_edict_t *edict;
6227
6228         GL_CullFace(GL_NONE);
6229         R_SetupShader_Generic_NoTexture(false, false);
6230
6231         for (i = 0;i < numsurfaces;i++)
6232         {
6233                 edict = PRVM_EDICT_NUM(surfacelist[i]);
6234                 switch ((int)PRVM_serveredictfloat(edict, solid))
6235                 {
6236                         case SOLID_NOT:      Vector4Set(color, 1, 1, 1, 0.05);break;
6237                         case SOLID_TRIGGER:  Vector4Set(color, 1, 0, 1, 0.10);break;
6238                         case SOLID_BBOX:     Vector4Set(color, 0, 1, 0, 0.10);break;
6239                         case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6240                         case SOLID_BSP:      Vector4Set(color, 0, 0, 1, 0.05);break;
6241                         case SOLID_CORPSE:   Vector4Set(color, 1, 0.5, 0, 0.05);break;
6242                         default:             Vector4Set(color, 0, 0, 0, 0.50);break;
6243                 }
6244                 if (prog == CLVM_prog)
6245                         color[3] *= r_showbboxes_client.value;
6246                 else
6247                         color[3] *= r_showbboxes.value;
6248                 color[3] = bound(0, color[3], 1);
6249                 GL_DepthTest(!r_showdisabledepthtest.integer);
6250                 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6251         }
6252 }
6253
6254 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6255 {
6256         int i;
6257         prvm_edict_t *edict;
6258         vec3_t center;
6259
6260         if (prog == NULL)
6261                 return;
6262
6263         for (i = 0; i < prog->num_edicts; i++)
6264         {
6265                 edict = PRVM_EDICT_NUM(i);
6266                 if (edict->priv.server->free)
6267                         continue;
6268                 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6269                 if (PRVM_serveredictedict(edict, tag_entity) != 0)
6270                         continue;
6271                 if (PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6272                         continue;
6273                 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6274                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6275         }
6276 }
6277
6278 static const int nomodelelement3i[24] =
6279 {
6280         5, 2, 0,
6281         5, 1, 2,
6282         5, 0, 3,
6283         5, 3, 1,
6284         0, 2, 4,
6285         2, 1, 4,
6286         3, 0, 4,
6287         1, 3, 4
6288 };
6289
6290 static const unsigned short nomodelelement3s[24] =
6291 {
6292         5, 2, 0,
6293         5, 1, 2,
6294         5, 0, 3,
6295         5, 3, 1,
6296         0, 2, 4,
6297         2, 1, 4,
6298         3, 0, 4,
6299         1, 3, 4
6300 };
6301
6302 static const float nomodelvertex3f[6*3] =
6303 {
6304         -16,   0,   0,
6305          16,   0,   0,
6306           0, -16,   0,
6307           0,  16,   0,
6308           0,   0, -16,
6309           0,   0,  16
6310 };
6311
6312 static const float nomodelcolor4f[6*4] =
6313 {
6314         0.0f, 0.0f, 0.5f, 1.0f,
6315         0.0f, 0.0f, 0.5f, 1.0f,
6316         0.0f, 0.5f, 0.0f, 1.0f,
6317         0.0f, 0.5f, 0.0f, 1.0f,
6318         0.5f, 0.0f, 0.0f, 1.0f,
6319         0.5f, 0.0f, 0.0f, 1.0f
6320 };
6321
6322 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6323 {
6324         int i;
6325         float f1, f2, *c;
6326         float color4f[6*4];
6327
6328         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);
6329
6330         // this is only called once per entity so numsurfaces is always 1, and
6331         // surfacelist is always {0}, so this code does not handle batches
6332
6333         if (rsurface.ent_flags & RENDER_ADDITIVE)
6334         {
6335                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6336                 GL_DepthMask(false);
6337         }
6338         else if (ent->alpha < 1)
6339         {
6340                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6341                 GL_DepthMask(false);
6342         }
6343         else
6344         {
6345                 GL_BlendFunc(GL_ONE, GL_ZERO);
6346                 GL_DepthMask(true);
6347         }
6348         GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6349         GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6350         GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6351         GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6352         memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6353         for (i = 0, c = color4f;i < 6;i++, c += 4)
6354         {
6355                 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6356                 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6357                 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6358                 c[3] *= ent->alpha;
6359         }
6360         if (r_refdef.fogenabled)
6361         {
6362                 for (i = 0, c = color4f;i < 6;i++, c += 4)
6363                 {
6364                         f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6365                         f2 = 1 - f1;
6366                         c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6367                         c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6368                         c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6369                 }
6370         }
6371 //      R_Mesh_ResetTextureState();
6372         R_SetupShader_Generic_NoTexture(false, false);
6373         R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6374         R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6375 }
6376
6377 void R_DrawNoModel(entity_render_t *ent)
6378 {
6379         vec3_t org;
6380         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6381         if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6382                 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6383         else
6384                 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6385 }
6386
6387 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6388 {
6389         vec3_t right1, right2, diff, normal;
6390
6391         VectorSubtract (org2, org1, normal);
6392
6393         // calculate 'right' vector for start
6394         VectorSubtract (r_refdef.view.origin, org1, diff);
6395         CrossProduct (normal, diff, right1);
6396         VectorNormalize (right1);
6397
6398         // calculate 'right' vector for end
6399         VectorSubtract (r_refdef.view.origin, org2, diff);
6400         CrossProduct (normal, diff, right2);
6401         VectorNormalize (right2);
6402
6403         vert[ 0] = org1[0] + width * right1[0];
6404         vert[ 1] = org1[1] + width * right1[1];
6405         vert[ 2] = org1[2] + width * right1[2];
6406         vert[ 3] = org1[0] - width * right1[0];
6407         vert[ 4] = org1[1] - width * right1[1];
6408         vert[ 5] = org1[2] - width * right1[2];
6409         vert[ 6] = org2[0] - width * right2[0];
6410         vert[ 7] = org2[1] - width * right2[1];
6411         vert[ 8] = org2[2] - width * right2[2];
6412         vert[ 9] = org2[0] + width * right2[0];
6413         vert[10] = org2[1] + width * right2[1];
6414         vert[11] = org2[2] + width * right2[2];
6415 }
6416
6417 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)
6418 {
6419         vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6420         vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6421         vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6422         vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6423         vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6424         vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6425         vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6426         vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6427         vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6428         vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6429         vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6430         vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6431 }
6432
6433 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6434 {
6435         int i;
6436         float *vertex3f;
6437         float v[3];
6438         VectorSet(v, x, y, z);
6439         for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6440                 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6441                         break;
6442         if (i == mesh->numvertices)
6443         {
6444                 if (mesh->numvertices < mesh->maxvertices)
6445                 {
6446                         VectorCopy(v, vertex3f);
6447                         mesh->numvertices++;
6448                 }
6449                 return mesh->numvertices;
6450         }
6451         else
6452                 return i;
6453 }
6454
6455 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6456 {
6457         int i;
6458         int *e, element[3];
6459         element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6460         element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6461         e = mesh->element3i + mesh->numtriangles * 3;
6462         for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6463         {
6464                 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6465                 if (mesh->numtriangles < mesh->maxtriangles)
6466                 {
6467                         *e++ = element[0];
6468                         *e++ = element[1];
6469                         *e++ = element[2];
6470                         mesh->numtriangles++;
6471                 }
6472                 element[1] = element[2];
6473         }
6474 }
6475
6476 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6477 {
6478         int i;
6479         int *e, element[3];
6480         element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6481         element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6482         e = mesh->element3i + mesh->numtriangles * 3;
6483         for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6484         {
6485                 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6486                 if (mesh->numtriangles < mesh->maxtriangles)
6487                 {
6488                         *e++ = element[0];
6489                         *e++ = element[1];
6490                         *e++ = element[2];
6491                         mesh->numtriangles++;
6492                 }
6493                 element[1] = element[2];
6494         }
6495 }
6496
6497 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6498 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6499 {
6500         int planenum, planenum2;
6501         int w;
6502         int tempnumpoints;
6503         mplane_t *plane, *plane2;
6504         double maxdist;
6505         double temppoints[2][256*3];
6506         // figure out how large a bounding box we need to properly compute this brush
6507         maxdist = 0;
6508         for (w = 0;w < numplanes;w++)
6509                 maxdist = max(maxdist, fabs(planes[w].dist));
6510         // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6511         maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6512         for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6513         {
6514                 w = 0;
6515                 tempnumpoints = 4;
6516                 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6517                 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6518                 {
6519                         if (planenum2 == planenum)
6520                                 continue;
6521                         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);
6522                         w = !w;
6523                 }
6524                 if (tempnumpoints < 3)
6525                         continue;
6526                 // generate elements forming a triangle fan for this polygon
6527                 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6528         }
6529 }
6530
6531 static void R_Texture_AddLayer(texture_t *t, qboolean depthmask, int blendfunc1, int blendfunc2, texturelayertype_t type, rtexture_t *texture, const matrix4x4_t *matrix, float r, float g, float b, float a)
6532 {
6533         texturelayer_t *layer;
6534         layer = t->currentlayers + t->currentnumlayers++;
6535         layer->type = type;
6536         layer->depthmask = depthmask;
6537         layer->blendfunc1 = blendfunc1;
6538         layer->blendfunc2 = blendfunc2;
6539         layer->texture = texture;
6540         layer->texmatrix = *matrix;
6541         layer->color[0] = r;
6542         layer->color[1] = g;
6543         layer->color[2] = b;
6544         layer->color[3] = a;
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 (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6783         {
6784                 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6785                 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT;
6786                 for (q = 0; q < 3; q++)
6787                 {
6788                         t->render_glowmod[q] = rsurface.entity->glowmod[q];
6789                         t->render_modellight_lightdir[q] = q == 2;
6790                         t->render_modellight_ambient[q] = 1;
6791                         t->render_modellight_diffuse[q] = 0;
6792                         t->render_modellight_specular[q] = 0;
6793                         t->render_lightmap_ambient[q] = 0;
6794                         t->render_lightmap_diffuse[q] = 0;
6795                         t->render_lightmap_specular[q] = 0;
6796                         t->render_rtlight_diffuse[q] = 0;
6797                         t->render_rtlight_specular[q] = 0;
6798                 }
6799         }
6800         else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6801         {
6802                 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6803                 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT;
6804                 for (q = 0; q < 3; q++)
6805                 {
6806                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6807                         t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6808                         t->render_modellight_lightdir[q] = q == 2;
6809                         t->render_modellight_diffuse[q] = 0;
6810                         t->render_modellight_specular[q] = 0;
6811                         t->render_lightmap_ambient[q] = 0;
6812                         t->render_lightmap_diffuse[q] = 0;
6813                         t->render_lightmap_specular[q] = 0;
6814                         t->render_rtlight_diffuse[q] = 0;
6815                         t->render_rtlight_specular[q] = 0;
6816                 }
6817         }
6818         else if (FAKELIGHT_ENABLED)
6819         {
6820                 // no modellight if using fakelight for the map
6821                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_NORTLIGHT) & ~(MATERIALFLAG_MODELLIGHT);
6822                 for (q = 0; q < 3; q++)
6823                 {
6824                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6825                         t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6826                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6827                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6828                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6829                         t->render_lightmap_ambient[q] = 0;
6830                         t->render_lightmap_diffuse[q] = 0;
6831                         t->render_lightmap_specular[q] = 0;
6832                         t->render_rtlight_diffuse[q] = 0;
6833                         t->render_rtlight_specular[q] = 0;
6834                 }
6835         }
6836         else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6837         {
6838                 // ambient + single direction light (modellight)
6839                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6840                 for (q = 0; q < 3; q++)
6841                 {
6842                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6843                         t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6844                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6845                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6846                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6847                         t->render_lightmap_ambient[q] = 0;
6848                         t->render_lightmap_diffuse[q] = 0;
6849                         t->render_lightmap_specular[q] = 0;
6850                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6851                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6852                 }
6853         }
6854         else
6855         {
6856                 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6857                 for (q = 0; q < 3; q++)
6858                 {
6859                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6860                         t->render_modellight_lightdir[q] = q == 2;
6861                         t->render_modellight_ambient[q] = 0;
6862                         t->render_modellight_diffuse[q] = 0;
6863                         t->render_modellight_specular[q] = 0;
6864                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6865                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6866                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6867                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6868                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6869                 }
6870         }
6871
6872         if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6873         {
6874                 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6875                 // attribute, we punt it to the lightmap path and hope for the best,
6876                 // but lighting doesn't work.
6877                 //
6878                 // FIXME: this is fine for effects but CSQC polygons should be subject
6879                 // to lighting.
6880                 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6881                 for (q = 0; q < 3; q++)
6882                 {
6883                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6884                         t->render_modellight_lightdir[q] = q == 2;
6885                         t->render_modellight_ambient[q] = 0;
6886                         t->render_modellight_diffuse[q] = 0;
6887                         t->render_modellight_specular[q] = 0;
6888                         t->render_lightmap_ambient[q] = 0;
6889                         t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6890                         t->render_lightmap_specular[q] = 0;
6891                         t->render_rtlight_diffuse[q] = 0;
6892                         t->render_rtlight_specular[q] = 0;
6893                 }
6894         }
6895
6896         for (q = 0; q < 3; q++)
6897         {
6898                 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6899                 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6900         }
6901
6902         if (rsurface.ent_flags & RENDER_ADDITIVE)
6903                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6904         else if (t->currentalpha < 1)
6905                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6906         // LordHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6907         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6908                 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6909         if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6910                 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6911         if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6912                 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6913         if (t->backgroundshaderpass)
6914                 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6915         if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6916         {
6917                 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6918                         t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6919         }
6920         else
6921                 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6922         if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6923         {
6924                 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6925                 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6926         }
6927         if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6928                 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6929
6930         // there is no tcmod
6931         if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6932         {
6933                 t->currenttexmatrix = r_waterscrollmatrix;
6934                 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6935         }
6936         else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6937         {
6938                 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6939                 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6940         }
6941
6942         if (t->materialshaderpass)
6943                 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6944                         R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6945
6946         t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6947         if (t->currentskinframe->qpixels)
6948                 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6949         t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6950         if (!t->basetexture)
6951                 t->basetexture = r_texture_notexture;
6952         t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6953         t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6954         t->nmaptexture = t->currentskinframe->nmap;
6955         if (!t->nmaptexture)
6956                 t->nmaptexture = r_texture_blanknormalmap;
6957         t->glosstexture = r_texture_black;
6958         t->glowtexture = t->currentskinframe->glow;
6959         t->fogtexture = t->currentskinframe->fog;
6960         t->reflectmasktexture = t->currentskinframe->reflect;
6961         if (t->backgroundshaderpass)
6962         {
6963                 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6964                         R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6965                 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6966                 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6967                 t->backgroundglosstexture = r_texture_black;
6968                 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6969                 if (!t->backgroundnmaptexture)
6970                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6971                 // make sure that if glow is going to be used, both textures are not NULL
6972                 if (!t->backgroundglowtexture && t->glowtexture)
6973                         t->backgroundglowtexture = r_texture_black;
6974                 if (!t->glowtexture && t->backgroundglowtexture)
6975                         t->glowtexture = r_texture_black;
6976         }
6977         else
6978         {
6979                 t->backgroundbasetexture = r_texture_white;
6980                 t->backgroundnmaptexture = r_texture_blanknormalmap;
6981                 t->backgroundglosstexture = r_texture_black;
6982                 t->backgroundglowtexture = NULL;
6983         }
6984         t->specularpower = r_shadow_glossexponent.value;
6985         // TODO: store reference values for these in the texture?
6986         if (r_shadow_gloss.integer > 0)
6987         {
6988                 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
6989                 {
6990                         if (r_shadow_glossintensity.value > 0)
6991                         {
6992                                 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
6993                                 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
6994                                 specularscale = r_shadow_glossintensity.value;
6995                         }
6996                 }
6997                 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
6998                 {
6999                         t->glosstexture = r_texture_white;
7000                         t->backgroundglosstexture = r_texture_white;
7001                         specularscale = r_shadow_gloss2intensity.value;
7002                         t->specularpower = r_shadow_gloss2exponent.value;
7003                 }
7004         }
7005         specularscale *= t->specularscalemod;
7006         t->specularpower *= t->specularpowermod;
7007
7008         // lightmaps mode looks bad with dlights using actual texturing, so turn
7009         // off the colormap and glossmap, but leave the normalmap on as it still
7010         // accurately represents the shading involved
7011         if (gl_lightmaps.integer)
7012         {
7013                 t->basetexture = r_texture_grey128;
7014                 t->pantstexture = r_texture_black;
7015                 t->shirttexture = r_texture_black;
7016                 if (gl_lightmaps.integer < 2)
7017                         t->nmaptexture = r_texture_blanknormalmap;
7018                 t->glosstexture = r_texture_black;
7019                 t->glowtexture = NULL;
7020                 t->fogtexture = NULL;
7021                 t->reflectmasktexture = NULL;
7022                 t->backgroundbasetexture = NULL;
7023                 if (gl_lightmaps.integer < 2)
7024                         t->backgroundnmaptexture = r_texture_blanknormalmap;
7025                 t->backgroundglosstexture = r_texture_black;
7026                 t->backgroundglowtexture = NULL;
7027                 specularscale = 0;
7028                 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
7029         }
7030
7031         if (specularscale != 1.0f)
7032         {
7033                 for (q = 0; q < 3; q++)
7034                 {
7035                         t->render_modellight_specular[q] *= specularscale;
7036                         t->render_lightmap_specular[q] *= specularscale;
7037                         t->render_rtlight_specular[q] *= specularscale;
7038                 }
7039         }
7040
7041         t->currentnumlayers = 0;
7042         if (t->currentmaterialflags & MATERIALFLAG_WALL)
7043         {
7044                 int blendfunc1, blendfunc2;
7045                 qboolean depthmask;
7046                 if (t->currentmaterialflags & MATERIALFLAG_ADD)
7047                 {
7048                         blendfunc1 = GL_SRC_ALPHA;
7049                         blendfunc2 = GL_ONE;
7050                 }
7051                 else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
7052                 {
7053                         blendfunc1 = GL_SRC_ALPHA;
7054                         blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
7055                 }
7056                 else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
7057                 {
7058                         blendfunc1 = t->customblendfunc[0];
7059                         blendfunc2 = t->customblendfunc[1];
7060                 }
7061                 else
7062                 {
7063                         blendfunc1 = GL_ONE;
7064                         blendfunc2 = GL_ZERO;
7065                 }
7066                 depthmask = !(t->currentmaterialflags & MATERIALFLAG_BLENDED);
7067                 if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
7068                 {
7069                         // basic lit geometry
7070                         R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE, t->basetexture, &t->currenttexmatrix, 2, 2, 2, t->currentalpha);
7071                         // add pants/shirt if needed
7072                         if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7073                                 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->pantstexture, &t->currenttexmatrix, 2 * t->render_colormap_pants[0], 2 * t->render_colormap_pants[1], 2 * t->render_colormap_pants[2], t->currentalpha);
7074                         if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7075                                 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->shirttexture, &t->currenttexmatrix, 2 * t->render_colormap_shirt[0], 2 * t->render_colormap_shirt[1], 2 * t->render_colormap_shirt[2], t->currentalpha);
7076                 }
7077                 else
7078                 {
7079                         // basic lit geometry
7080                         R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE, t->basetexture, &t->currenttexmatrix, t->render_lightmap_diffuse[0], t->render_lightmap_diffuse[1], t->render_lightmap_diffuse[2], t->currentalpha);
7081                         // add pants/shirt if needed
7082                         if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7083                                 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->pantstexture, &t->currenttexmatrix, t->render_colormap_pants[0] * t->render_lightmap_diffuse[0], t->render_colormap_pants[1] * t->render_lightmap_diffuse[1], t->render_colormap_pants[2]  * t->render_lightmap_diffuse[2], t->currentalpha);
7084                         if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7085                                 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->shirttexture, &t->currenttexmatrix, t->render_colormap_shirt[0] * t->render_lightmap_diffuse[0], t->render_colormap_shirt[1] * t->render_lightmap_diffuse[1], t->render_colormap_shirt[2] * t->render_lightmap_diffuse[2], t->currentalpha);
7086                         // now add ambient passes if needed
7087                         if (VectorLength2(t->render_lightmap_ambient) >= (1.0f/1048576.0f))
7088                         {
7089                                 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->basetexture, &t->currenttexmatrix, t->render_lightmap_ambient[0], t->render_lightmap_ambient[1], t->render_lightmap_ambient[2], t->currentalpha);
7090                                 if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7091                                         R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->pantstexture, &t->currenttexmatrix, t->render_colormap_pants[0] * t->render_lightmap_ambient[0], t->render_colormap_pants[1] * t->render_lightmap_ambient[1], t->render_colormap_pants[2] * t->render_lightmap_ambient[2], t->currentalpha);
7092                                 if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7093                                         R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->shirttexture, &t->currenttexmatrix, t->render_colormap_shirt[0] * t->render_lightmap_ambient[0], t->render_colormap_shirt[1] * t->render_lightmap_ambient[1], t->render_colormap_shirt[2] * t->render_lightmap_ambient[2], t->currentalpha);
7094                         }
7095                 }
7096                 if (t->glowtexture != NULL && !gl_lightmaps.integer)
7097                         R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->glowtexture, &t->currenttexmatrix, t->render_glowmod[0], t->render_glowmod[1], t->render_glowmod[2], t->currentalpha);
7098                 if (r_refdef.fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD))
7099                 {
7100                         // if this is opaque use alpha blend which will darken the earlier
7101                         // passes cheaply.
7102                         //
7103                         // if this is an alpha blended material, all the earlier passes
7104                         // were darkened by fog already, so we only need to add the fog
7105                         // color ontop through the fog mask texture
7106                         //
7107                         // if this is an additive blended material, all the earlier passes
7108                         // were darkened by fog already, and we should not add fog color
7109                         // (because the background was not darkened, there is no fog color
7110                         // that was lost behind it).
7111                         R_Texture_AddLayer(t, false, GL_SRC_ALPHA, (t->currentmaterialflags & MATERIALFLAG_BLENDED) ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA, TEXTURELAYERTYPE_FOG, t->fogtexture, &t->currenttexmatrix, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], t->currentalpha);
7112                 }
7113         }
7114
7115         return t;
7116 }
7117
7118 rsurfacestate_t rsurface;
7119
7120 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
7121 {
7122         dp_model_t *model = ent->model;
7123         //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
7124         //      return;
7125         rsurface.entity = (entity_render_t *)ent;
7126         rsurface.skeleton = ent->skeleton;
7127         memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
7128         rsurface.ent_skinnum = ent->skinnum;
7129         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;
7130         rsurface.ent_flags = ent->flags;
7131         if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
7132                 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
7133         rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
7134         rsurface.matrix = ent->matrix;
7135         rsurface.inversematrix = ent->inversematrix;
7136         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7137         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7138         R_EntityMatrix(&rsurface.matrix);
7139         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7140         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7141         rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
7142         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7143         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7144         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7145         memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
7146         rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
7147         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7148         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7149         if (ent->model->brush.submodel && !prepass)
7150         {
7151                 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
7152                 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
7153         }
7154         // if the animcache code decided it should use the shader path, skip the deform step
7155         rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
7156         rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
7157         rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
7158         rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
7159         rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
7160         if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
7161         {
7162                 if (ent->animcache_vertex3f)
7163                 {
7164                         r_refdef.stats[r_stat_batch_entitycache_count]++;
7165                         r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
7166                         r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
7167                         r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
7168                         rsurface.modelvertex3f = ent->animcache_vertex3f;
7169                         rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
7170                         rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
7171                         rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
7172                         rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
7173                         rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
7174                         rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
7175                         rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
7176                         rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
7177                         rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
7178                         rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
7179                         rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
7180                         rsurface.modelvertexmesh = ent->animcache_vertexmesh;
7181                         rsurface.modelvertexmesh_vertexbuffer = ent->animcache_vertexmesh_vertexbuffer;
7182                         rsurface.modelvertexmesh_bufferoffset = ent->animcache_vertexmesh_bufferoffset;
7183                 }
7184                 else if (wanttangents)
7185                 {
7186                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7187                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7188                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7189                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7190                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7191                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7192                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7193                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7194                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
7195                         rsurface.modelvertexmesh = NULL;
7196                         rsurface.modelvertexmesh_vertexbuffer = NULL;
7197                         rsurface.modelvertexmesh_bufferoffset = 0;
7198                         rsurface.modelvertex3f_vertexbuffer = NULL;
7199                         rsurface.modelvertex3f_bufferoffset = 0;
7200                         rsurface.modelvertex3f_vertexbuffer = 0;
7201                         rsurface.modelvertex3f_bufferoffset = 0;
7202                         rsurface.modelsvector3f_vertexbuffer = 0;
7203                         rsurface.modelsvector3f_bufferoffset = 0;
7204                         rsurface.modeltvector3f_vertexbuffer = 0;
7205                         rsurface.modeltvector3f_bufferoffset = 0;
7206                         rsurface.modelnormal3f_vertexbuffer = 0;
7207                         rsurface.modelnormal3f_bufferoffset = 0;
7208                 }
7209                 else if (wantnormals)
7210                 {
7211                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7212                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7213                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7214                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7215                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7216                         rsurface.modelsvector3f = NULL;
7217                         rsurface.modeltvector3f = NULL;
7218                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7219                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
7220                         rsurface.modelvertexmesh = NULL;
7221                         rsurface.modelvertexmesh_vertexbuffer = NULL;
7222                         rsurface.modelvertexmesh_bufferoffset = 0;
7223                         rsurface.modelvertex3f_vertexbuffer = NULL;
7224                         rsurface.modelvertex3f_bufferoffset = 0;
7225                         rsurface.modelvertex3f_vertexbuffer = 0;
7226                         rsurface.modelvertex3f_bufferoffset = 0;
7227                         rsurface.modelsvector3f_vertexbuffer = 0;
7228                         rsurface.modelsvector3f_bufferoffset = 0;
7229                         rsurface.modeltvector3f_vertexbuffer = 0;
7230                         rsurface.modeltvector3f_bufferoffset = 0;
7231                         rsurface.modelnormal3f_vertexbuffer = 0;
7232                         rsurface.modelnormal3f_bufferoffset = 0;
7233                 }
7234                 else
7235                 {
7236                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7237                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7238                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7239                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7240                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7241                         rsurface.modelsvector3f = NULL;
7242                         rsurface.modeltvector3f = NULL;
7243                         rsurface.modelnormal3f = NULL;
7244                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7245                         rsurface.modelvertexmesh = NULL;
7246                         rsurface.modelvertexmesh_vertexbuffer = NULL;
7247                         rsurface.modelvertexmesh_bufferoffset = 0;
7248                         rsurface.modelvertex3f_vertexbuffer = NULL;
7249                         rsurface.modelvertex3f_bufferoffset = 0;
7250                         rsurface.modelvertex3f_vertexbuffer = 0;
7251                         rsurface.modelvertex3f_bufferoffset = 0;
7252                         rsurface.modelsvector3f_vertexbuffer = 0;
7253                         rsurface.modelsvector3f_bufferoffset = 0;
7254                         rsurface.modeltvector3f_vertexbuffer = 0;
7255                         rsurface.modeltvector3f_bufferoffset = 0;
7256                         rsurface.modelnormal3f_vertexbuffer = 0;
7257                         rsurface.modelnormal3f_bufferoffset = 0;
7258                 }
7259                 rsurface.modelgeneratedvertex = true;
7260         }
7261         else
7262         {
7263                 if (rsurface.entityskeletaltransform3x4)
7264                 {
7265                         r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7266                         r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7267                         r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7268                         r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7269                 }
7270                 else
7271                 {
7272                         r_refdef.stats[r_stat_batch_entitystatic_count]++;
7273                         r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7274                         r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7275                         r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7276                 }
7277                 rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
7278                 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7279                 rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
7280                 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7281                 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7282                 rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f;
7283                 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7284                 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7285                 rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f;
7286                 rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
7287                 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7288                 rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f;
7289                 rsurface.modelvertexmesh = model->surfmesh.data_vertexmesh;
7290                 rsurface.modelvertexmesh_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7291                 rsurface.modelvertexmesh_bufferoffset = model->surfmesh.vbooffset_vertex3f;
7292                 rsurface.modelgeneratedvertex = false;
7293         }
7294         rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
7295         rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7296         rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f;
7297         rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
7298         rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7299         rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f;
7300         rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
7301         rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7302         rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
7303         rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7304         rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7305         rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.vbooffset_skeletalindex4ub;
7306         rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7307         rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7308         rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.vbooffset_skeletalweight4ub;
7309         rsurface.modelelement3i = model->surfmesh.data_element3i;
7310         rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7311         rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7312         rsurface.modelelement3s = model->surfmesh.data_element3s;
7313         rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7314         rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7315         rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7316         rsurface.modelnumvertices = model->surfmesh.num_vertices;
7317         rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7318         rsurface.modelsurfaces = model->data_surfaces;
7319         rsurface.batchgeneratedvertex = false;
7320         rsurface.batchfirstvertex = 0;
7321         rsurface.batchnumvertices = 0;
7322         rsurface.batchfirsttriangle = 0;
7323         rsurface.batchnumtriangles = 0;
7324         rsurface.batchvertex3f  = NULL;
7325         rsurface.batchvertex3f_vertexbuffer = NULL;
7326         rsurface.batchvertex3f_bufferoffset = 0;
7327         rsurface.batchsvector3f = NULL;
7328         rsurface.batchsvector3f_vertexbuffer = NULL;
7329         rsurface.batchsvector3f_bufferoffset = 0;
7330         rsurface.batchtvector3f = NULL;
7331         rsurface.batchtvector3f_vertexbuffer = NULL;
7332         rsurface.batchtvector3f_bufferoffset = 0;
7333         rsurface.batchnormal3f  = NULL;
7334         rsurface.batchnormal3f_vertexbuffer = NULL;
7335         rsurface.batchnormal3f_bufferoffset = 0;
7336         rsurface.batchlightmapcolor4f = NULL;
7337         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7338         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7339         rsurface.batchtexcoordtexture2f = NULL;
7340         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7341         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7342         rsurface.batchtexcoordlightmap2f = NULL;
7343         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7344         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7345         rsurface.batchskeletalindex4ub = NULL;
7346         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7347         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7348         rsurface.batchskeletalweight4ub = NULL;
7349         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7350         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7351         rsurface.batchvertexmesh = NULL;
7352         rsurface.batchvertexmesh_vertexbuffer = NULL;
7353         rsurface.batchvertexmesh_bufferoffset = 0;
7354         rsurface.batchelement3i = NULL;
7355         rsurface.batchelement3i_indexbuffer = NULL;
7356         rsurface.batchelement3i_bufferoffset = 0;
7357         rsurface.batchelement3s = NULL;
7358         rsurface.batchelement3s_indexbuffer = NULL;
7359         rsurface.batchelement3s_bufferoffset = 0;
7360         rsurface.forcecurrenttextureupdate = false;
7361 }
7362
7363 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)
7364 {
7365         rsurface.entity = r_refdef.scene.worldentity;
7366         rsurface.skeleton = NULL;
7367         rsurface.ent_skinnum = 0;
7368         rsurface.ent_qwskin = -1;
7369         rsurface.ent_flags = entflags;
7370         rsurface.shadertime = r_refdef.scene.time - shadertime;
7371         rsurface.modelnumvertices = numvertices;
7372         rsurface.modelnumtriangles = numtriangles;
7373         rsurface.matrix = *matrix;
7374         rsurface.inversematrix = *inversematrix;
7375         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7376         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7377         R_EntityMatrix(&rsurface.matrix);
7378         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7379         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7380         rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7381         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7382         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7383         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7384         memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7385         rsurface.frameblend[0].lerp = 1;
7386         rsurface.ent_alttextures = false;
7387         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7388         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7389         rsurface.entityskeletaltransform3x4 = NULL;
7390         rsurface.entityskeletaltransform3x4buffer = NULL;
7391         rsurface.entityskeletaltransform3x4offset = 0;
7392         rsurface.entityskeletaltransform3x4size = 0;
7393         rsurface.entityskeletalnumtransforms = 0;
7394         r_refdef.stats[r_stat_batch_entitycustom_count]++;
7395         r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7396         r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7397         r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7398         if (wanttangents)
7399         {
7400                 rsurface.modelvertex3f = (float *)vertex3f;
7401                 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7402                 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7403                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7404         }
7405         else if (wantnormals)
7406         {
7407                 rsurface.modelvertex3f = (float *)vertex3f;
7408                 rsurface.modelsvector3f = NULL;
7409                 rsurface.modeltvector3f = NULL;
7410                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7411         }
7412         else
7413         {
7414                 rsurface.modelvertex3f = (float *)vertex3f;
7415                 rsurface.modelsvector3f = NULL;
7416                 rsurface.modeltvector3f = NULL;
7417                 rsurface.modelnormal3f = NULL;
7418         }
7419         rsurface.modelvertexmesh = NULL;
7420         rsurface.modelvertexmesh_vertexbuffer = NULL;
7421         rsurface.modelvertexmesh_bufferoffset = 0;
7422         rsurface.modelvertex3f_vertexbuffer = 0;
7423         rsurface.modelvertex3f_bufferoffset = 0;
7424         rsurface.modelsvector3f_vertexbuffer = 0;
7425         rsurface.modelsvector3f_bufferoffset = 0;
7426         rsurface.modeltvector3f_vertexbuffer = 0;
7427         rsurface.modeltvector3f_bufferoffset = 0;
7428         rsurface.modelnormal3f_vertexbuffer = 0;
7429         rsurface.modelnormal3f_bufferoffset = 0;
7430         rsurface.modelgeneratedvertex = true;
7431         rsurface.modellightmapcolor4f  = (float *)color4f;
7432         rsurface.modellightmapcolor4f_vertexbuffer = 0;
7433         rsurface.modellightmapcolor4f_bufferoffset = 0;
7434         rsurface.modeltexcoordtexture2f  = (float *)texcoord2f;
7435         rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7436         rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7437         rsurface.modeltexcoordlightmap2f  = NULL;
7438         rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7439         rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7440         rsurface.modelskeletalindex4ub = NULL;
7441         rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7442         rsurface.modelskeletalindex4ub_bufferoffset = 0;
7443         rsurface.modelskeletalweight4ub = NULL;
7444         rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7445         rsurface.modelskeletalweight4ub_bufferoffset = 0;
7446         rsurface.modelelement3i = (int *)element3i;
7447         rsurface.modelelement3i_indexbuffer = NULL;
7448         rsurface.modelelement3i_bufferoffset = 0;
7449         rsurface.modelelement3s = (unsigned short *)element3s;
7450         rsurface.modelelement3s_indexbuffer = NULL;
7451         rsurface.modelelement3s_bufferoffset = 0;
7452         rsurface.modellightmapoffsets = NULL;
7453         rsurface.modelsurfaces = NULL;
7454         rsurface.batchgeneratedvertex = false;
7455         rsurface.batchfirstvertex = 0;
7456         rsurface.batchnumvertices = 0;
7457         rsurface.batchfirsttriangle = 0;
7458         rsurface.batchnumtriangles = 0;
7459         rsurface.batchvertex3f  = NULL;
7460         rsurface.batchvertex3f_vertexbuffer = NULL;
7461         rsurface.batchvertex3f_bufferoffset = 0;
7462         rsurface.batchsvector3f = NULL;
7463         rsurface.batchsvector3f_vertexbuffer = NULL;
7464         rsurface.batchsvector3f_bufferoffset = 0;
7465         rsurface.batchtvector3f = NULL;
7466         rsurface.batchtvector3f_vertexbuffer = NULL;
7467         rsurface.batchtvector3f_bufferoffset = 0;
7468         rsurface.batchnormal3f  = NULL;
7469         rsurface.batchnormal3f_vertexbuffer = NULL;
7470         rsurface.batchnormal3f_bufferoffset = 0;
7471         rsurface.batchlightmapcolor4f = NULL;
7472         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7473         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7474         rsurface.batchtexcoordtexture2f = NULL;
7475         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7476         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7477         rsurface.batchtexcoordlightmap2f = NULL;
7478         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7479         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7480         rsurface.batchskeletalindex4ub = NULL;
7481         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7482         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7483         rsurface.batchskeletalweight4ub = NULL;
7484         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7485         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7486         rsurface.batchvertexmesh = NULL;
7487         rsurface.batchvertexmesh_vertexbuffer = NULL;
7488         rsurface.batchvertexmesh_bufferoffset = 0;
7489         rsurface.batchelement3i = NULL;
7490         rsurface.batchelement3i_indexbuffer = NULL;
7491         rsurface.batchelement3i_bufferoffset = 0;
7492         rsurface.batchelement3s = NULL;
7493         rsurface.batchelement3s_indexbuffer = NULL;
7494         rsurface.batchelement3s_bufferoffset = 0;
7495         rsurface.forcecurrenttextureupdate = true;
7496
7497         if (rsurface.modelnumvertices && rsurface.modelelement3i)
7498         {
7499                 if ((wantnormals || wanttangents) && !normal3f)
7500                 {
7501                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7502                         Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7503                 }
7504                 if (wanttangents && !svector3f)
7505                 {
7506                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7507                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7508                         Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7509                 }
7510         }
7511 }
7512
7513 float RSurf_FogPoint(const float *v)
7514 {
7515         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7516         float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7517         float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7518         float FogHeightFade = r_refdef.fogheightfade;
7519         float fogfrac;
7520         unsigned int fogmasktableindex;
7521         if (r_refdef.fogplaneviewabove)
7522                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7523         else
7524                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7525         fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7526         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7527 }
7528
7529 float RSurf_FogVertex(const float *v)
7530 {
7531         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7532         float FogPlaneViewDist = rsurface.fogplaneviewdist;
7533         float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7534         float FogHeightFade = rsurface.fogheightfade;
7535         float fogfrac;
7536         unsigned int fogmasktableindex;
7537         if (r_refdef.fogplaneviewabove)
7538                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7539         else
7540                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7541         fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7542         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7543 }
7544
7545 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7546 {
7547         int i;
7548         for (i = 0;i < numelements;i++)
7549                 outelement3i[i] = inelement3i[i] + adjust;
7550 }
7551
7552 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7553 extern cvar_t gl_vbo;
7554 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7555 {
7556         int deformindex;
7557         int firsttriangle;
7558         int numtriangles;
7559         int firstvertex;
7560         int endvertex;
7561         int numvertices;
7562         int surfacefirsttriangle;
7563         int surfacenumtriangles;
7564         int surfacefirstvertex;
7565         int surfaceendvertex;
7566         int surfacenumvertices;
7567         int batchnumsurfaces = texturenumsurfaces;
7568         int batchnumvertices;
7569         int batchnumtriangles;
7570         int needsupdate;
7571         int i, j;
7572         qboolean gaps;
7573         qboolean dynamicvertex;
7574         float amplitude;
7575         float animpos;
7576         float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7577         float waveparms[4];
7578         unsigned char *ub;
7579         q3shaderinfo_deform_t *deform;
7580         const msurface_t *surface, *firstsurface;
7581         r_vertexmesh_t *vertexmesh;
7582         if (!texturenumsurfaces)
7583                 return;
7584         // find vertex range of this surface batch
7585         gaps = false;
7586         firstsurface = texturesurfacelist[0];
7587         firsttriangle = firstsurface->num_firsttriangle;
7588         batchnumvertices = 0;
7589         batchnumtriangles = 0;
7590         firstvertex = endvertex = firstsurface->num_firstvertex;
7591         for (i = 0;i < texturenumsurfaces;i++)
7592         {
7593                 surface = texturesurfacelist[i];
7594                 if (surface != firstsurface + i)
7595                         gaps = true;
7596                 surfacefirstvertex = surface->num_firstvertex;
7597                 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7598                 surfacenumvertices = surface->num_vertices;
7599                 surfacenumtriangles = surface->num_triangles;
7600                 if (firstvertex > surfacefirstvertex)
7601                         firstvertex = surfacefirstvertex;
7602                 if (endvertex < surfaceendvertex)
7603                         endvertex = surfaceendvertex;
7604                 batchnumvertices += surfacenumvertices;
7605                 batchnumtriangles += surfacenumtriangles;
7606         }
7607
7608         r_refdef.stats[r_stat_batch_batches]++;
7609         if (gaps)
7610                 r_refdef.stats[r_stat_batch_withgaps]++;
7611         r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7612         r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7613         r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7614
7615         // we now know the vertex range used, and if there are any gaps in it
7616         rsurface.batchfirstvertex = firstvertex;
7617         rsurface.batchnumvertices = endvertex - firstvertex;
7618         rsurface.batchfirsttriangle = firsttriangle;
7619         rsurface.batchnumtriangles = batchnumtriangles;
7620
7621         // this variable holds flags for which properties have been updated that
7622         // may require regenerating vertexmesh array...
7623         needsupdate = 0;
7624
7625         // check if any dynamic vertex processing must occur
7626         dynamicvertex = false;
7627
7628         // a cvar to force the dynamic vertex path to be taken, for debugging
7629         if (r_batch_debugdynamicvertexpath.integer)
7630         {
7631                 if (!dynamicvertex)
7632                 {
7633                         r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7634                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7635                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7636                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7637                 }
7638                 dynamicvertex = true;
7639         }
7640
7641         // if there is a chance of animated vertex colors, it's a dynamic batch
7642         if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo)
7643         {
7644                 if (!dynamicvertex)
7645                 {
7646                         r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7647                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7648                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7649                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7650                 }
7651                 dynamicvertex = true;
7652                 needsupdate |= BATCHNEED_VERTEXMESH_VERTEXCOLOR;
7653         }
7654
7655         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7656         {
7657                 switch (deform->deform)
7658                 {
7659                 default:
7660                 case Q3DEFORM_PROJECTIONSHADOW:
7661                 case Q3DEFORM_TEXT0:
7662                 case Q3DEFORM_TEXT1:
7663                 case Q3DEFORM_TEXT2:
7664                 case Q3DEFORM_TEXT3:
7665                 case Q3DEFORM_TEXT4:
7666                 case Q3DEFORM_TEXT5:
7667                 case Q3DEFORM_TEXT6:
7668                 case Q3DEFORM_TEXT7:
7669                 case Q3DEFORM_NONE:
7670                         break;
7671                 case Q3DEFORM_AUTOSPRITE:
7672                         if (!dynamicvertex)
7673                         {
7674                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7675                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7676                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7677                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7678                         }
7679                         dynamicvertex = true;
7680                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7681                         needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7682                         break;
7683                 case Q3DEFORM_AUTOSPRITE2:
7684                         if (!dynamicvertex)
7685                         {
7686                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7687                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7688                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7689                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7690                         }
7691                         dynamicvertex = true;
7692                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7693                         needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7694                         break;
7695                 case Q3DEFORM_NORMAL:
7696                         if (!dynamicvertex)
7697                         {
7698                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7699                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7700                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7701                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7702                         }
7703                         dynamicvertex = true;
7704                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7705                         needsupdate |= BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7706                         break;
7707                 case Q3DEFORM_WAVE:
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_wave] += 1;
7713                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7714                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7715                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7716                         }
7717                         dynamicvertex = true;
7718                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7719                         needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7720                         break;
7721                 case Q3DEFORM_BULGE:
7722                         if (!dynamicvertex)
7723                         {
7724                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7725                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7726                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7727                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7728                         }
7729                         dynamicvertex = true;
7730                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7731                         needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7732                         break;
7733                 case Q3DEFORM_MOVE:
7734                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7735                                 break; // if wavefunc is a nop, ignore this transform
7736                         if (!dynamicvertex)
7737                         {
7738                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7739                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7740                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7741                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7742                         }
7743                         dynamicvertex = true;
7744                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7745                         needsupdate |= BATCHNEED_VERTEXMESH_VERTEX;
7746                         break;
7747                 }
7748         }
7749         if (rsurface.texture->materialshaderpass)
7750         {
7751                 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7752                 {
7753                 default:
7754                 case Q3TCGEN_TEXTURE:
7755                         break;
7756                 case Q3TCGEN_LIGHTMAP:
7757                         if (!dynamicvertex)
7758                         {
7759                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7760                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7761                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7762                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7763                         }
7764                         dynamicvertex = true;
7765                         batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7766                         needsupdate |= BATCHNEED_VERTEXMESH_LIGHTMAP;
7767                         break;
7768                 case Q3TCGEN_VECTOR:
7769                         if (!dynamicvertex)
7770                         {
7771                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7772                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7773                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7774                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7775                         }
7776                         dynamicvertex = true;
7777                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7778                         needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
7779                         break;
7780                 case Q3TCGEN_ENVIRONMENT:
7781                         if (!dynamicvertex)
7782                         {
7783                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7784                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7785                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7786                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7787                         }
7788                         dynamicvertex = true;
7789                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7790                         needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
7791                         break;
7792                 }
7793                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7794                 {
7795                         if (!dynamicvertex)
7796                         {
7797                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7798                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7799                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7800                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7801                         }
7802                         dynamicvertex = true;
7803                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7804                         needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
7805                 }
7806         }
7807
7808         if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)))
7809         {
7810                 if (!dynamicvertex)
7811                 {
7812                         r_refdef.stats[r_stat_batch_dynamic_batches_because_interleavedarrays] += 1;
7813                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_interleavedarrays] += batchnumsurfaces;
7814                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_interleavedarrays] += batchnumvertices;
7815                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_interleavedarrays] += batchnumtriangles;
7816                 }
7817                 dynamicvertex = true;
7818                 needsupdate |= (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP));
7819         }
7820
7821         // when the model data has no vertex buffer (dynamic mesh), we need to
7822         // eliminate gaps
7823         if (vid.useinterleavedarrays && !rsurface.modelvertexmesh_vertexbuffer)
7824                 batchneed |= BATCHNEED_NOGAPS;
7825
7826         // the caller can specify BATCHNEED_NOGAPS to force a batch with
7827         // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7828         // we ensure this by treating the vertex batch as dynamic...
7829         if ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0))
7830         {
7831                 if (!dynamicvertex)
7832                 {
7833                         r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7834                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7835                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7836                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7837                 }
7838                 dynamicvertex = true;
7839         }
7840
7841         if (dynamicvertex)
7842         {
7843                 // when copying, we need to consider the regeneration of vertexmesh, any dependencies it may have must be set...
7844                 if (batchneed & BATCHNEED_VERTEXMESH_VERTEX)      batchneed |= BATCHNEED_ARRAY_VERTEX;
7845                 if (batchneed & BATCHNEED_VERTEXMESH_NORMAL)      batchneed |= BATCHNEED_ARRAY_NORMAL;
7846                 if (batchneed & BATCHNEED_VERTEXMESH_VECTOR)      batchneed |= BATCHNEED_ARRAY_VECTOR;
7847                 if (batchneed & BATCHNEED_VERTEXMESH_VERTEXCOLOR) batchneed |= BATCHNEED_ARRAY_VERTEXCOLOR;
7848                 if (batchneed & BATCHNEED_VERTEXMESH_TEXCOORD)    batchneed |= BATCHNEED_ARRAY_TEXCOORD;
7849                 if (batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP)    batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7850                 if (batchneed & BATCHNEED_VERTEXMESH_SKELETAL)    batchneed |= BATCHNEED_ARRAY_SKELETAL;
7851         }
7852
7853         // if needsupdate, we have to do a dynamic vertex batch for sure
7854         if (needsupdate & batchneed)
7855         {
7856                 if (!dynamicvertex)
7857                 {
7858                         r_refdef.stats[r_stat_batch_dynamic_batches_because_derived] += 1;
7859                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_derived] += batchnumsurfaces;
7860                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_derived] += batchnumvertices;
7861                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_derived] += batchnumtriangles;
7862                 }
7863                 dynamicvertex = true;
7864         }
7865
7866         // see if we need to build vertexmesh from arrays
7867         if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)))
7868         {
7869                 if (!dynamicvertex)
7870                 {
7871                         r_refdef.stats[r_stat_batch_dynamic_batches_because_interleavedarrays] += 1;
7872                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_interleavedarrays] += batchnumsurfaces;
7873                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_interleavedarrays] += batchnumvertices;
7874                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_interleavedarrays] += batchnumtriangles;
7875                 }
7876                 dynamicvertex = true;
7877         }
7878
7879         // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7880         if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7881                 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7882
7883         rsurface.batchvertex3f = rsurface.modelvertex3f;
7884         rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7885         rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7886         rsurface.batchsvector3f = rsurface.modelsvector3f;
7887         rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7888         rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7889         rsurface.batchtvector3f = rsurface.modeltvector3f;
7890         rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7891         rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7892         rsurface.batchnormal3f = rsurface.modelnormal3f;
7893         rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7894         rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7895         rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7896         rsurface.batchlightmapcolor4f_vertexbuffer  = rsurface.modellightmapcolor4f_vertexbuffer;
7897         rsurface.batchlightmapcolor4f_bufferoffset  = rsurface.modellightmapcolor4f_bufferoffset;
7898         rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7899         rsurface.batchtexcoordtexture2f_vertexbuffer  = rsurface.modeltexcoordtexture2f_vertexbuffer;
7900         rsurface.batchtexcoordtexture2f_bufferoffset  = rsurface.modeltexcoordtexture2f_bufferoffset;
7901         rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7902         rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7903         rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7904         rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7905         rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7906         rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7907         rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7908         rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7909         rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7910         rsurface.batchvertexmesh = rsurface.modelvertexmesh;
7911         rsurface.batchvertexmesh_vertexbuffer = rsurface.modelvertexmesh_vertexbuffer;
7912         rsurface.batchvertexmesh_bufferoffset = rsurface.modelvertexmesh_bufferoffset;
7913         rsurface.batchelement3i = rsurface.modelelement3i;
7914         rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7915         rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7916         rsurface.batchelement3s = rsurface.modelelement3s;
7917         rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7918         rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7919         rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7920         rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7921         rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7922         rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7923         rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7924
7925         // if any dynamic vertex processing has to occur in software, we copy the
7926         // entire surface list together before processing to rebase the vertices
7927         // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7928         //
7929         // if any gaps exist and we do not have a static vertex buffer, we have to
7930         // copy the surface list together to avoid wasting upload bandwidth on the
7931         // vertices in the gaps.
7932         //
7933         // if gaps exist and we have a static vertex buffer, we can choose whether
7934         // to combine the index buffer ranges into one dynamic index buffer or
7935         // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7936         //
7937         // in many cases the batch is reduced to one draw call.
7938
7939         rsurface.batchmultidraw = false;
7940         rsurface.batchmultidrawnumsurfaces = 0;
7941         rsurface.batchmultidrawsurfacelist = NULL;
7942
7943         if (!dynamicvertex)
7944         {
7945                 // static vertex data, just set pointers...
7946                 rsurface.batchgeneratedvertex = false;
7947                 // if there are gaps, we want to build a combined index buffer,
7948                 // otherwise use the original static buffer with an appropriate offset
7949                 if (gaps)
7950                 {
7951                         r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7952                         r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7953                         r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7954                         r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7955                         if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7956                         {
7957                                 rsurface.batchmultidraw = true;
7958                                 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7959                                 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7960                                 return;
7961                         }
7962                         // build a new triangle elements array for this batch
7963                         rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7964                         rsurface.batchfirsttriangle = 0;
7965                         numtriangles = 0;
7966                         for (i = 0;i < texturenumsurfaces;i++)
7967                         {
7968                                 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7969                                 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7970                                 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7971                                 numtriangles += surfacenumtriangles;
7972                         }
7973                         rsurface.batchelement3i_indexbuffer = NULL;
7974                         rsurface.batchelement3i_bufferoffset = 0;
7975                         rsurface.batchelement3s = NULL;
7976                         rsurface.batchelement3s_indexbuffer = NULL;
7977                         rsurface.batchelement3s_bufferoffset = 0;
7978                         if (endvertex <= 65536)
7979                         {
7980                                 // make a 16bit (unsigned short) index array if possible
7981                                 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7982                                 for (i = 0;i < numtriangles*3;i++)
7983                                         rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7984                         }
7985                         // upload buffer data for the copytriangles batch
7986                         if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo)
7987                         {
7988                                 if (rsurface.batchelement3s)
7989                                         rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
7990                                 else if (rsurface.batchelement3i)
7991                                         rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
7992                         }
7993                 }
7994                 else
7995                 {
7996                         r_refdef.stats[r_stat_batch_fast_batches] += 1;
7997                         r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
7998                         r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
7999                         r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
8000                 }
8001                 return;
8002         }
8003
8004         // something needs software processing, do it for real...
8005         // we only directly handle separate array data in this case and then
8006         // generate interleaved data if needed...
8007         rsurface.batchgeneratedvertex = true;
8008         r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
8009         r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
8010         r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
8011         r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
8012
8013         // now copy the vertex data into a combined array and make an index array
8014         // (this is what Quake3 does all the time)
8015         // we also apply any skeletal animation here that would have been done in
8016         // the vertex shader, because most of the dynamic vertex animation cases
8017         // need actual vertex positions and normals
8018         //if (dynamicvertex)
8019         {
8020                 rsurface.batchvertexmesh = NULL;
8021                 rsurface.batchvertexmesh_vertexbuffer = NULL;
8022                 rsurface.batchvertexmesh_bufferoffset = 0;
8023                 rsurface.batchvertex3f = NULL;
8024                 rsurface.batchvertex3f_vertexbuffer = NULL;
8025                 rsurface.batchvertex3f_bufferoffset = 0;
8026                 rsurface.batchsvector3f = NULL;
8027                 rsurface.batchsvector3f_vertexbuffer = NULL;
8028                 rsurface.batchsvector3f_bufferoffset = 0;
8029                 rsurface.batchtvector3f = NULL;
8030                 rsurface.batchtvector3f_vertexbuffer = NULL;
8031                 rsurface.batchtvector3f_bufferoffset = 0;
8032                 rsurface.batchnormal3f = NULL;
8033                 rsurface.batchnormal3f_vertexbuffer = NULL;
8034                 rsurface.batchnormal3f_bufferoffset = 0;
8035                 rsurface.batchlightmapcolor4f = NULL;
8036                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8037                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8038                 rsurface.batchtexcoordtexture2f = NULL;
8039                 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8040                 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8041                 rsurface.batchtexcoordlightmap2f = NULL;
8042                 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
8043                 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
8044                 rsurface.batchskeletalindex4ub = NULL;
8045                 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
8046                 rsurface.batchskeletalindex4ub_bufferoffset = 0;
8047                 rsurface.batchskeletalweight4ub = NULL;
8048                 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
8049                 rsurface.batchskeletalweight4ub_bufferoffset = 0;
8050                 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
8051                 rsurface.batchelement3i_indexbuffer = NULL;
8052                 rsurface.batchelement3i_bufferoffset = 0;
8053                 rsurface.batchelement3s = NULL;
8054                 rsurface.batchelement3s_indexbuffer = NULL;
8055                 rsurface.batchelement3s_bufferoffset = 0;
8056                 rsurface.batchskeletaltransform3x4buffer = NULL;
8057                 rsurface.batchskeletaltransform3x4offset = 0;
8058                 rsurface.batchskeletaltransform3x4size = 0;
8059                 // we'll only be setting up certain arrays as needed
8060                 if (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP))
8061                         rsurface.batchvertexmesh = (r_vertexmesh_t *)R_FrameData_Alloc(batchnumvertices * sizeof(r_vertexmesh_t));
8062                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
8063                         rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8064                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
8065                         rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8066                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
8067                 {
8068                         rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8069                         rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8070                 }
8071                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
8072                         rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8073                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
8074                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8075                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
8076                         rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8077                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
8078                 {
8079                         rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
8080                         rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
8081                 }
8082                 numvertices = 0;
8083                 numtriangles = 0;
8084                 for (i = 0;i < texturenumsurfaces;i++)
8085                 {
8086                         surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
8087                         surfacenumvertices = texturesurfacelist[i]->num_vertices;
8088                         surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
8089                         surfacenumtriangles = texturesurfacelist[i]->num_triangles;
8090                         // copy only the data requested
8091                         if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)) && rsurface.modelvertexmesh)
8092                                 memcpy(rsurface.batchvertexmesh + numvertices, rsurface.modelvertexmesh + surfacefirstvertex, surfacenumvertices * sizeof(rsurface.batchvertexmesh[0]));
8093                         if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
8094                         {
8095                                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
8096                                 {
8097                                         if (rsurface.batchvertex3f)
8098                                                 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8099                                         else
8100                                                 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8101                                 }
8102                                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
8103                                 {
8104                                         if (rsurface.modelnormal3f)
8105                                                 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8106                                         else
8107                                                 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8108                                 }
8109                                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
8110                                 {
8111                                         if (rsurface.modelsvector3f)
8112                                         {
8113                                                 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8114                                                 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8115                                         }
8116                                         else
8117                                         {
8118                                                 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8119                                                 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8120                                         }
8121                                 }
8122                                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
8123                                 {
8124                                         if (rsurface.modellightmapcolor4f)
8125                                                 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
8126                                         else
8127                                                 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
8128                                 }
8129                                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
8130                                 {
8131                                         if (rsurface.modeltexcoordtexture2f)
8132                                                 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
8133                                         else
8134                                                 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
8135                                 }
8136                                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
8137                                 {
8138                                         if (rsurface.modeltexcoordlightmap2f)
8139                                                 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
8140                                         else
8141                                                 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
8142                                 }
8143                                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
8144                                 {
8145                                         if (rsurface.modelskeletalindex4ub)
8146                                         {
8147                                                 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
8148                                                 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
8149                                         }
8150                                         else
8151                                         {
8152                                                 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
8153                                                 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
8154                                                 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
8155                                                 for (j = 0;j < surfacenumvertices;j++)
8156                                                         ub[j*4] = 255;
8157                                         }
8158                                 }
8159                         }
8160                         RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
8161                         numvertices += surfacenumvertices;
8162                         numtriangles += surfacenumtriangles;
8163                 }
8164
8165                 // generate a 16bit index array as well if possible
8166                 // (in general, dynamic batches fit)
8167                 if (numvertices <= 65536)
8168                 {
8169                         rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
8170                         for (i = 0;i < numtriangles*3;i++)
8171                                 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
8172                 }
8173
8174                 // since we've copied everything, the batch now starts at 0
8175                 rsurface.batchfirstvertex = 0;
8176                 rsurface.batchnumvertices = batchnumvertices;
8177                 rsurface.batchfirsttriangle = 0;
8178                 rsurface.batchnumtriangles = batchnumtriangles;
8179         }
8180
8181         // apply skeletal animation that would have been done in the vertex shader
8182         if (rsurface.batchskeletaltransform3x4)
8183         {
8184                 const unsigned char *si;
8185                 const unsigned char *sw;
8186                 const float *t[4];
8187                 const float *b = rsurface.batchskeletaltransform3x4;
8188                 float *vp, *vs, *vt, *vn;
8189                 float w[4];
8190                 float m[3][4], n[3][4];
8191                 float tp[3], ts[3], tt[3], tn[3];
8192                 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
8193                 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
8194                 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
8195                 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
8196                 si = rsurface.batchskeletalindex4ub;
8197                 sw = rsurface.batchskeletalweight4ub;
8198                 vp = rsurface.batchvertex3f;
8199                 vs = rsurface.batchsvector3f;
8200                 vt = rsurface.batchtvector3f;
8201                 vn = rsurface.batchnormal3f;
8202                 memset(m[0], 0, sizeof(m));
8203                 memset(n[0], 0, sizeof(n));
8204                 for (i = 0;i < batchnumvertices;i++)
8205                 {
8206                         t[0] = b + si[0]*12;
8207                         if (sw[0] == 255)
8208                         {
8209                                 // common case - only one matrix
8210                                 m[0][0] = t[0][ 0];
8211                                 m[0][1] = t[0][ 1];
8212                                 m[0][2] = t[0][ 2];
8213                                 m[0][3] = t[0][ 3];
8214                                 m[1][0] = t[0][ 4];
8215                                 m[1][1] = t[0][ 5];
8216                                 m[1][2] = t[0][ 6];
8217                                 m[1][3] = t[0][ 7];
8218                                 m[2][0] = t[0][ 8];
8219                                 m[2][1] = t[0][ 9];
8220                                 m[2][2] = t[0][10];
8221                                 m[2][3] = t[0][11];
8222                         }
8223                         else if (sw[2] + sw[3])
8224                         {
8225                                 // blend 4 matrices
8226                                 t[1] = b + si[1]*12;
8227                                 t[2] = b + si[2]*12;
8228                                 t[3] = b + si[3]*12;
8229                                 w[0] = sw[0] * (1.0f / 255.0f);
8230                                 w[1] = sw[1] * (1.0f / 255.0f);
8231                                 w[2] = sw[2] * (1.0f / 255.0f);
8232                                 w[3] = sw[3] * (1.0f / 255.0f);
8233                                 // blend the matrices
8234                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
8235                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
8236                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
8237                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
8238                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
8239                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
8240                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
8241                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
8242                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
8243                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
8244                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
8245                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
8246                         }
8247                         else
8248                         {
8249                                 // blend 2 matrices
8250                                 t[1] = b + si[1]*12;
8251                                 w[0] = sw[0] * (1.0f / 255.0f);
8252                                 w[1] = sw[1] * (1.0f / 255.0f);
8253                                 // blend the matrices
8254                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
8255                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
8256                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
8257                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
8258                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
8259                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
8260                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
8261                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
8262                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
8263                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
8264                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
8265                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
8266                         }
8267                         si += 4;
8268                         sw += 4;
8269                         // modify the vertex
8270                         VectorCopy(vp, tp);
8271                         vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
8272                         vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
8273                         vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
8274                         vp += 3;
8275                         if (vn)
8276                         {
8277                                 // the normal transformation matrix is a set of cross products...
8278                                 CrossProduct(m[1], m[2], n[0]);
8279                                 CrossProduct(m[2], m[0], n[1]);
8280                                 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8281                                 VectorCopy(vn, tn);
8282                                 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8283                                 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8284                                 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8285                                 VectorNormalize(vn);
8286                                 vn += 3;
8287                                 if (vs)
8288                                 {
8289                                         VectorCopy(vs, ts);
8290                                         vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8291                                         vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8292                                         vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8293                                         VectorNormalize(vs);
8294                                         vs += 3;
8295                                         VectorCopy(vt, tt);
8296                                         vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8297                                         vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8298                                         vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8299                                         VectorNormalize(vt);
8300                                         vt += 3;
8301                                 }
8302                         }
8303                 }
8304                 rsurface.batchskeletaltransform3x4 = NULL;
8305                 rsurface.batchskeletalnumtransforms = 0;
8306         }
8307
8308         // q1bsp surfaces rendered in vertex color mode have to have colors
8309         // calculated based on lightstyles
8310         if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo)
8311         {
8312                 // generate color arrays for the surfaces in this list
8313                 int c[4];
8314                 int scale;
8315                 int size3;
8316                 const int *offsets;
8317                 const unsigned char *lm;
8318                 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8319                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8320                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8321                 numvertices = 0;
8322                 for (i = 0;i < texturenumsurfaces;i++)
8323                 {
8324                         surface = texturesurfacelist[i];
8325                         offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8326                         surfacenumvertices = surface->num_vertices;
8327                         if (surface->lightmapinfo->samples)
8328                         {
8329                                 for (j = 0;j < surfacenumvertices;j++)
8330                                 {
8331                                         lm = surface->lightmapinfo->samples + offsets[j];
8332                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8333                                         VectorScale(lm, scale, c);
8334                                         if (surface->lightmapinfo->styles[1] != 255)
8335                                         {
8336                                                 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8337                                                 lm += size3;
8338                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8339                                                 VectorMA(c, scale, lm, c);
8340                                                 if (surface->lightmapinfo->styles[2] != 255)
8341                                                 {
8342                                                         lm += size3;
8343                                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8344                                                         VectorMA(c, scale, lm, c);
8345                                                         if (surface->lightmapinfo->styles[3] != 255)
8346                                                         {
8347                                                                 lm += size3;
8348                                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8349                                                                 VectorMA(c, scale, lm, c);
8350                                                         }
8351                                                 }
8352                                         }
8353                                         c[0] >>= 7;
8354                                         c[1] >>= 7;
8355                                         c[2] >>= 7;
8356                                         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);
8357                                         numvertices++;
8358                                 }
8359                         }
8360                         else
8361                         {
8362                                 for (j = 0;j < surfacenumvertices;j++)
8363                                 {
8364                                         Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8365                                         numvertices++;
8366                                 }
8367                         }
8368                 }
8369         }
8370
8371         // if vertices are deformed (sprite flares and things in maps, possibly
8372         // water waves, bulges and other deformations), modify the copied vertices
8373         // in place
8374         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8375         {
8376                 float scale;
8377                 switch (deform->deform)
8378                 {
8379                 default:
8380                 case Q3DEFORM_PROJECTIONSHADOW:
8381                 case Q3DEFORM_TEXT0:
8382                 case Q3DEFORM_TEXT1:
8383                 case Q3DEFORM_TEXT2:
8384                 case Q3DEFORM_TEXT3:
8385                 case Q3DEFORM_TEXT4:
8386                 case Q3DEFORM_TEXT5:
8387                 case Q3DEFORM_TEXT6:
8388                 case Q3DEFORM_TEXT7:
8389                 case Q3DEFORM_NONE:
8390                         break;
8391                 case Q3DEFORM_AUTOSPRITE:
8392                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8393                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8394                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8395                         VectorNormalize(newforward);
8396                         VectorNormalize(newright);
8397                         VectorNormalize(newup);
8398 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8399 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8400 //                      rsurface.batchvertex3f_bufferoffset = 0;
8401 //                      rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8402 //                      rsurface.batchsvector3f_vertexbuffer = NULL;
8403 //                      rsurface.batchsvector3f_bufferoffset = 0;
8404 //                      rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8405 //                      rsurface.batchtvector3f_vertexbuffer = NULL;
8406 //                      rsurface.batchtvector3f_bufferoffset = 0;
8407 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8408 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8409 //                      rsurface.batchnormal3f_bufferoffset = 0;
8410                         // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8411                         if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8412                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8413                         if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8414                                 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);
8415                         // a single autosprite surface can contain multiple sprites...
8416                         for (j = 0;j < batchnumvertices - 3;j += 4)
8417                         {
8418                                 VectorClear(center);
8419                                 for (i = 0;i < 4;i++)
8420                                         VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8421                                 VectorScale(center, 0.25f, center);
8422                                 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8423                                 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8424                                 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8425                                 for (i = 0;i < 4;i++)
8426                                 {
8427                                         VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8428                                         VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8429                                 }
8430                         }
8431                         // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8432                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 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                         break;
8435                 case Q3DEFORM_AUTOSPRITE2:
8436                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8437                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8438                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8439                         VectorNormalize(newforward);
8440                         VectorNormalize(newright);
8441                         VectorNormalize(newup);
8442 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8443 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8444 //                      rsurface.batchvertex3f_bufferoffset = 0;
8445                         {
8446                                 const float *v1, *v2;
8447                                 vec3_t start, end;
8448                                 float f, l;
8449                                 struct
8450                                 {
8451                                         float length2;
8452                                         const float *v1;
8453                                         const float *v2;
8454                                 }
8455                                 shortest[2];
8456                                 memset(shortest, 0, sizeof(shortest));
8457                                 // a single autosprite surface can contain multiple sprites...
8458                                 for (j = 0;j < batchnumvertices - 3;j += 4)
8459                                 {
8460                                         VectorClear(center);
8461                                         for (i = 0;i < 4;i++)
8462                                                 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8463                                         VectorScale(center, 0.25f, center);
8464                                         // find the two shortest edges, then use them to define the
8465                                         // axis vectors for rotating around the central axis
8466                                         for (i = 0;i < 6;i++)
8467                                         {
8468                                                 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8469                                                 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8470                                                 l = VectorDistance2(v1, v2);
8471                                                 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8472                                                 if (v1[2] != v2[2])
8473                                                         l += (1.0f / 1024.0f);
8474                                                 if (shortest[0].length2 > l || i == 0)
8475                                                 {
8476                                                         shortest[1] = shortest[0];
8477                                                         shortest[0].length2 = l;
8478                                                         shortest[0].v1 = v1;
8479                                                         shortest[0].v2 = v2;
8480                                                 }
8481                                                 else if (shortest[1].length2 > l || i == 1)
8482                                                 {
8483                                                         shortest[1].length2 = l;
8484                                                         shortest[1].v1 = v1;
8485                                                         shortest[1].v2 = v2;
8486                                                 }
8487                                         }
8488                                         VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8489                                         VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8490                                         // this calculates the right vector from the shortest edge
8491                                         // and the up vector from the edge midpoints
8492                                         VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8493                                         VectorNormalize(right);
8494                                         VectorSubtract(end, start, up);
8495                                         VectorNormalize(up);
8496                                         // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8497                                         VectorSubtract(rsurface.localvieworigin, center, forward);
8498                                         //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8499                                         VectorNegate(forward, forward);
8500                                         VectorReflect(forward, 0, up, forward);
8501                                         VectorNormalize(forward);
8502                                         CrossProduct(up, forward, newright);
8503                                         VectorNormalize(newright);
8504                                         // rotate the quad around the up axis vector, this is made
8505                                         // especially easy by the fact we know the quad is flat,
8506                                         // so we only have to subtract the center position and
8507                                         // measure distance along the right vector, and then
8508                                         // multiply that by the newright vector and add back the
8509                                         // center position
8510                                         // we also need to subtract the old position to undo the
8511                                         // displacement from the center, which we do with a
8512                                         // DotProduct, the subtraction/addition of center is also
8513                                         // optimized into DotProducts here
8514                                         l = DotProduct(right, center);
8515                                         for (i = 0;i < 4;i++)
8516                                         {
8517                                                 v1 = rsurface.batchvertex3f + 3*(j+i);
8518                                                 f = DotProduct(right, v1) - l;
8519                                                 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8520                                         }
8521                                 }
8522                         }
8523                         if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8524                         {
8525 //                              rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8526 //                              rsurface.batchnormal3f_vertexbuffer = NULL;
8527 //                              rsurface.batchnormal3f_bufferoffset = 0;
8528                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8529                         }
8530                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8531                         {
8532 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8533 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8534 //                              rsurface.batchsvector3f_bufferoffset = 0;
8535 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8536 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8537 //                              rsurface.batchtvector3f_bufferoffset = 0;
8538                                 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);
8539                         }
8540                         break;
8541                 case Q3DEFORM_NORMAL:
8542                         // deform the normals to make reflections wavey
8543                         rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8544                         rsurface.batchnormal3f_vertexbuffer = NULL;
8545                         rsurface.batchnormal3f_bufferoffset = 0;
8546                         for (j = 0;j < batchnumvertices;j++)
8547                         {
8548                                 float vertex[3];
8549                                 float *normal = rsurface.batchnormal3f + 3*j;
8550                                 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8551                                 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8552                                 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8553                                 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8554                                 VectorNormalize(normal);
8555                         }
8556                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8557                         {
8558 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8559 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8560 //                              rsurface.batchsvector3f_bufferoffset = 0;
8561 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8562 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8563 //                              rsurface.batchtvector3f_bufferoffset = 0;
8564                                 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);
8565                         }
8566                         break;
8567                 case Q3DEFORM_WAVE:
8568                         // deform vertex array to make wavey water and flags and such
8569                         waveparms[0] = deform->waveparms[0];
8570                         waveparms[1] = deform->waveparms[1];
8571                         waveparms[2] = deform->waveparms[2];
8572                         waveparms[3] = deform->waveparms[3];
8573                         if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8574                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8575                         // this is how a divisor of vertex influence on deformation
8576                         animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8577                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8578 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8579 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8580 //                      rsurface.batchvertex3f_bufferoffset = 0;
8581 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8582 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8583 //                      rsurface.batchnormal3f_bufferoffset = 0;
8584                         for (j = 0;j < batchnumvertices;j++)
8585                         {
8586                                 // if the wavefunc depends on time, evaluate it per-vertex
8587                                 if (waveparms[3])
8588                                 {
8589                                         waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8590                                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8591                                 }
8592                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8593                         }
8594                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8595                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8596                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8597                         {
8598 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8599 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8600 //                              rsurface.batchsvector3f_bufferoffset = 0;
8601 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8602 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8603 //                              rsurface.batchtvector3f_bufferoffset = 0;
8604                                 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);
8605                         }
8606                         break;
8607                 case Q3DEFORM_BULGE:
8608                         // deform vertex array to make the surface have moving bulges
8609 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8610 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8611 //                      rsurface.batchvertex3f_bufferoffset = 0;
8612 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8613 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8614 //                      rsurface.batchnormal3f_bufferoffset = 0;
8615                         for (j = 0;j < batchnumvertices;j++)
8616                         {
8617                                 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8618                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8619                         }
8620                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8621                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8622                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8623                         {
8624 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8625 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8626 //                              rsurface.batchsvector3f_bufferoffset = 0;
8627 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8628 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8629 //                              rsurface.batchtvector3f_bufferoffset = 0;
8630                                 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);
8631                         }
8632                         break;
8633                 case Q3DEFORM_MOVE:
8634                         // deform vertex array
8635                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8636                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8637                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8638                         VectorScale(deform->parms, scale, waveparms);
8639 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8640 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8641 //                      rsurface.batchvertex3f_bufferoffset = 0;
8642                         for (j = 0;j < batchnumvertices;j++)
8643                                 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8644                         break;
8645                 }
8646         }
8647
8648         if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8649         {
8650         // generate texcoords based on the chosen texcoord source
8651                 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8652                 {
8653                 default:
8654                 case Q3TCGEN_TEXTURE:
8655                         break;
8656                 case Q3TCGEN_LIGHTMAP:
8657         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8658         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8659         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8660                         if (rsurface.batchtexcoordlightmap2f)
8661                                 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8662                         break;
8663                 case Q3TCGEN_VECTOR:
8664         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8665         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8666         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8667                         for (j = 0;j < batchnumvertices;j++)
8668                         {
8669                                 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8670                                 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8671                         }
8672                         break;
8673                 case Q3TCGEN_ENVIRONMENT:
8674                         // make environment reflections using a spheremap
8675                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8676                         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8677                         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8678                         for (j = 0;j < batchnumvertices;j++)
8679                         {
8680                                 // identical to Q3A's method, but executed in worldspace so
8681                                 // carried models can be shiny too
8682
8683                                 float viewer[3], d, reflected[3], worldreflected[3];
8684
8685                                 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8686                                 // VectorNormalize(viewer);
8687
8688                                 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8689
8690                                 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8691                                 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8692                                 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8693                                 // note: this is proportinal to viewer, so we can normalize later
8694
8695                                 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8696                                 VectorNormalize(worldreflected);
8697
8698                                 // note: this sphere map only uses world x and z!
8699                                 // so positive and negative y will LOOK THE SAME.
8700                                 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8701                                 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8702                         }
8703                         break;
8704                 }
8705                 // the only tcmod that needs software vertex processing is turbulent, so
8706                 // check for it here and apply the changes if needed
8707                 // and we only support that as the first one
8708                 // (handling a mixture of turbulent and other tcmods would be problematic
8709                 //  without punting it entirely to a software path)
8710                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8711                 {
8712                         amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8713                         animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8714         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8715         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8716         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8717                         for (j = 0;j < batchnumvertices;j++)
8718                         {
8719                                 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);
8720                                 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8721                         }
8722                 }
8723         }
8724
8725         if (needsupdate & batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP))
8726         {
8727                 // convert the modified arrays to vertex structs
8728 //              rsurface.batchvertexmesh = R_FrameData_Alloc(batchnumvertices * sizeof(r_vertexmesh_t));
8729 //              rsurface.batchvertexmesh_vertexbuffer = NULL;
8730 //              rsurface.batchvertexmesh_bufferoffset = 0;
8731                 if (batchneed & BATCHNEED_VERTEXMESH_VERTEX)
8732                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8733                                 VectorCopy(rsurface.batchvertex3f + 3*j, vertexmesh->vertex3f);
8734                 if (batchneed & BATCHNEED_VERTEXMESH_NORMAL)
8735                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8736                                 VectorCopy(rsurface.batchnormal3f + 3*j, vertexmesh->normal3f);
8737                 if (batchneed & BATCHNEED_VERTEXMESH_VECTOR)
8738                 {
8739                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8740                         {
8741                                 VectorCopy(rsurface.batchsvector3f + 3*j, vertexmesh->svector3f);
8742                                 VectorCopy(rsurface.batchtvector3f + 3*j, vertexmesh->tvector3f);
8743                         }
8744                 }
8745                 if ((batchneed & BATCHNEED_VERTEXMESH_VERTEXCOLOR) && rsurface.batchlightmapcolor4f)
8746                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8747                                 Vector4Copy(rsurface.batchlightmapcolor4f + 4*j, vertexmesh->color4f);
8748                 if (batchneed & BATCHNEED_VERTEXMESH_TEXCOORD)
8749                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8750                                 Vector2Copy(rsurface.batchtexcoordtexture2f + 2*j, vertexmesh->texcoordtexture2f);
8751                 if ((batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP) && rsurface.batchtexcoordlightmap2f)
8752                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8753                                 Vector2Copy(rsurface.batchtexcoordlightmap2f + 2*j, vertexmesh->texcoordlightmap2f);
8754                 if ((batchneed & BATCHNEED_VERTEXMESH_SKELETAL) && rsurface.batchskeletalindex4ub)
8755                 {
8756                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8757                         {
8758                                 Vector4Copy(rsurface.batchskeletalindex4ub + 4*j, vertexmesh->skeletalindex4ub);
8759                                 Vector4Copy(rsurface.batchskeletalweight4ub + 4*j, vertexmesh->skeletalweight4ub);
8760                         }
8761                 }
8762         }
8763
8764         // upload buffer data for the dynamic batch
8765         if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicvertex.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo)
8766         {
8767                 if (rsurface.batchvertexmesh)
8768                         rsurface.batchvertexmesh_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(r_vertexmesh_t), rsurface.batchvertexmesh, R_BUFFERDATA_VERTEX, &rsurface.batchvertexmesh_bufferoffset);
8769                 else
8770                 {
8771                         if (rsurface.batchvertex3f)
8772                                 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
8773                         if (rsurface.batchsvector3f)
8774                                 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
8775                         if (rsurface.batchtvector3f)
8776                                 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
8777                         if (rsurface.batchnormal3f)
8778                                 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
8779                         if (rsurface.batchlightmapcolor4f)
8780                                 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
8781                         if (rsurface.batchtexcoordtexture2f)
8782                                 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
8783                         if (rsurface.batchtexcoordlightmap2f)
8784                                 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
8785                         if (rsurface.batchskeletalindex4ub)
8786                                 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
8787                         if (rsurface.batchskeletalweight4ub)
8788                                 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
8789                 }
8790                 if (rsurface.batchelement3s)
8791                         rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
8792                 else if (rsurface.batchelement3i)
8793                         rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
8794         }
8795 }
8796
8797 void RSurf_DrawBatch(void)
8798 {
8799         // sometimes a zero triangle surface (usually a degenerate patch) makes it
8800         // through the pipeline, killing it earlier in the pipeline would have
8801         // per-surface overhead rather than per-batch overhead, so it's best to
8802         // reject it here, before it hits glDraw.
8803         if (rsurface.batchnumtriangles == 0)
8804                 return;
8805 #if 0
8806         // batch debugging code
8807         if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8808         {
8809                 int i;
8810                 int j;
8811                 int c;
8812                 const int *e;
8813                 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8814                 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8815                 {
8816                         c = e[i];
8817                         for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8818                         {
8819                                 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8820                                 {
8821                                         if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8822                                                 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);
8823                                         break;
8824                                 }
8825                         }
8826                 }
8827         }
8828 #endif
8829         if (rsurface.batchmultidraw)
8830         {
8831                 // issue multiple draws rather than copying index data
8832                 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8833                 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8834                 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8835                 for (i = 0;i < numsurfaces;)
8836                 {
8837                         // combine consecutive surfaces as one draw
8838                         for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8839                                 if (surfacelist[j] != surfacelist[k] + 1)
8840                                         break;
8841                         firstvertex = surfacelist[i]->num_firstvertex;
8842                         endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8843                         firsttriangle = surfacelist[i]->num_firsttriangle;
8844                         endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8845                         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);
8846                         i = j;
8847                 }
8848         }
8849         else
8850         {
8851                 // there is only one consecutive run of index data (may have been combined)
8852                 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);
8853         }
8854 }
8855
8856 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8857 {
8858         // pick the closest matching water plane
8859         int planeindex, vertexindex, bestplaneindex = -1;
8860         float d, bestd;
8861         vec3_t vert;
8862         const float *v;
8863         r_waterstate_waterplane_t *p;
8864         qboolean prepared = false;
8865         bestd = 0;
8866         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8867         {
8868                 if(p->camera_entity != rsurface.texture->camera_entity)
8869                         continue;
8870                 d = 0;
8871                 if(!prepared)
8872                 {
8873                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8874                         prepared = true;
8875                         if(rsurface.batchnumvertices == 0)
8876                                 break;
8877                 }
8878                 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8879                 {
8880                         Matrix4x4_Transform(&rsurface.matrix, v, vert);
8881                         d += fabs(PlaneDiff(vert, &p->plane));
8882                 }
8883                 if (bestd > d || bestplaneindex < 0)
8884                 {
8885                         bestd = d;
8886                         bestplaneindex = planeindex;
8887                 }
8888         }
8889         return bestplaneindex;
8890         // NOTE: this MAY return a totally unrelated water plane; we can ignore
8891         // this situation though, as it might be better to render single larger
8892         // batches with useless stuff (backface culled for example) than to
8893         // render multiple smaller batches
8894 }
8895
8896 void RSurf_SetupDepthAndCulling(void)
8897 {
8898         // submodels are biased to avoid z-fighting with world surfaces that they
8899         // may be exactly overlapping (avoids z-fighting artifacts on certain
8900         // doors and things in Quake maps)
8901         GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8902         GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8903         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8904         GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8905 }
8906
8907 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8908 {
8909         int i, j;
8910         // transparent sky would be ridiculous
8911         if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8912                 return;
8913         R_SetupShader_Generic_NoTexture(false, false);
8914         skyrenderlater = true;
8915         RSurf_SetupDepthAndCulling();
8916         GL_DepthMask(true);
8917
8918         // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8919         if (r_sky_scissor.integer)
8920         {
8921                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8922                 for (i = 0; i < texturenumsurfaces; i++)
8923                 {
8924                         const msurface_t *surf = texturesurfacelist[i];
8925                         const float *v;
8926                         float p[3];
8927                         float mins[3], maxs[3];
8928                         int scissor[4];
8929                         for (j = 0, v = rsurface.batchvertex3f + 3 * surf->num_firstvertex; j < surf->num_vertices; j++, v += 3)
8930                         {
8931                                 Matrix4x4_Transform(&rsurface.matrix, v, p);
8932                                 if (j > 0)
8933                                 {
8934                                         if (mins[0] > p[0]) mins[0] = p[0];
8935                                         if (mins[1] > p[1]) mins[1] = p[1];
8936                                         if (mins[2] > p[2]) mins[2] = p[2];
8937                                         if (maxs[0] < p[0]) maxs[0] = p[0];
8938                                         if (maxs[1] < p[1]) maxs[1] = p[1];
8939                                         if (maxs[2] < p[2]) maxs[2] = p[2];
8940                                 }
8941                                 else
8942                                 {
8943                                         VectorCopy(p, mins);
8944                                         VectorCopy(p, maxs);
8945                                 }
8946                         }
8947                         if (!R_ScissorForBBox(mins, maxs, scissor))
8948                         {
8949                                 if (skyscissor[2])
8950                                 {
8951                                         if (skyscissor[0] > scissor[0])
8952                                         {
8953                                                 skyscissor[2] += skyscissor[0] - scissor[0];
8954                                                 skyscissor[0] = scissor[0];
8955                                         }
8956                                         if (skyscissor[1] > scissor[1])
8957                                         {
8958                                                 skyscissor[3] += skyscissor[1] - scissor[1];
8959                                                 skyscissor[1] = scissor[1];
8960                                         }
8961                                         if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8962                                                 skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8963                                         if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8964                                                 skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8965                                 }
8966                                 else
8967                                         Vector4Copy(scissor, skyscissor);
8968                         }
8969                 }
8970         }
8971
8972         // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8973         // skymasking on them, and Quake3 never did sky masking (unlike
8974         // software Quake and software Quake2), so disable the sky masking
8975         // in Quake3 maps as it causes problems with q3map2 sky tricks,
8976         // and skymasking also looks very bad when noclipping outside the
8977         // level, so don't use it then either.
8978         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)
8979         {
8980                 R_Mesh_ResetTextureState();
8981                 if (skyrendermasked)
8982                 {
8983                         R_SetupShader_DepthOrShadow(false, false, false);
8984                         // depth-only (masking)
8985                         GL_ColorMask(0, 0, 0, 0);
8986                         // just to make sure that braindead drivers don't draw
8987                         // anything despite that colormask...
8988                         GL_BlendFunc(GL_ZERO, GL_ONE);
8989                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8990                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8991                 }
8992                 else
8993                 {
8994                         R_SetupShader_Generic_NoTexture(false, false);
8995                         // fog sky
8996                         GL_BlendFunc(GL_ONE, GL_ZERO);
8997                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8998                         GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
8999                         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9000                 }
9001                 RSurf_DrawBatch();
9002                 if (skyrendermasked)
9003                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
9004         }
9005         R_Mesh_ResetTextureState();
9006         GL_Color(1, 1, 1, 1);
9007 }
9008
9009 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
9010 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
9011 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
9012 {
9013         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
9014                 return;
9015         if (prepass)
9016         {
9017                 // render screenspace normalmap to texture
9018                 GL_DepthMask(true);
9019                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false);
9020                 RSurf_DrawBatch();
9021                 return;
9022         }
9023
9024         // bind lightmap texture
9025
9026         // water/refraction/reflection/camera surfaces have to be handled specially
9027         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
9028         {
9029                 int start, end, startplaneindex;
9030                 for (start = 0;start < texturenumsurfaces;start = end)
9031                 {
9032                         startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
9033                         if(startplaneindex < 0)
9034                         {
9035                                 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
9036                                 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
9037                                 end = start + 1;
9038                                 continue;
9039                         }
9040                         for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
9041                                 ;
9042                         // now that we have a batch using the same planeindex, render it
9043                         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
9044                         {
9045                                 // render water or distortion background
9046                                 GL_DepthMask(true);
9047                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
9048                                 RSurf_DrawBatch();
9049                                 // blend surface on top
9050                                 GL_DepthMask(false);
9051                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false);
9052                                 RSurf_DrawBatch();
9053                         }
9054                         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
9055                         {
9056                                 // render surface with reflection texture as input
9057                                 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
9058                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
9059                                 RSurf_DrawBatch();
9060                         }
9061                 }
9062                 return;
9063         }
9064
9065         // render surface batch normally
9066         GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
9067         R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0);
9068         RSurf_DrawBatch();
9069 }
9070
9071 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
9072 {
9073         int vi;
9074         int j;
9075         r_vertexgeneric_t *batchvertex;
9076         float c[4];
9077         texture_t *t = rsurface.texture;
9078
9079 //      R_Mesh_ResetTextureState();
9080         R_SetupShader_Generic_NoTexture(false, false);
9081
9082         if(t && t->currentskinframe)
9083         {
9084                 memcpy(c, t->currentskinframe->avgcolor, sizeof(c));
9085                 c[3] *= t->currentalpha;
9086         }
9087         else
9088         {
9089                 c[0] = 1;
9090                 c[1] = 0;
9091                 c[2] = 1;
9092                 c[3] = 1;
9093         }
9094
9095         if (t->pantstexture || t->shirttexture)
9096         {
9097                 c[0] = 0.5 * (t->render_colormap_pants[0] * 0.3 + t->render_colormap_shirt[0] * 0.7);
9098                 c[1] = 0.5 * (t->render_colormap_pants[1] * 0.3 + t->render_colormap_shirt[1] * 0.7);
9099                 c[2] = 0.5 * (t->render_colormap_pants[2] * 0.3 + t->render_colormap_shirt[2] * 0.7);
9100         }
9101
9102         // brighten it up (as texture value 127 means "unlit")
9103         c[0] *= 2 * r_refdef.view.colorscale;
9104         c[1] *= 2 * r_refdef.view.colorscale;
9105         c[2] *= 2 * r_refdef.view.colorscale;
9106
9107         if(t->currentmaterialflags & MATERIALFLAG_WATERALPHA)
9108                 c[3] *= r_wateralpha.value;
9109
9110         if(t->currentmaterialflags & MATERIALFLAG_ALPHA && c[3] != 1)
9111         {
9112                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9113                 GL_DepthMask(false);
9114         }
9115         else if(t->currentmaterialflags & MATERIALFLAG_ADD)
9116         {
9117                 GL_BlendFunc(GL_ONE, GL_ONE);
9118                 GL_DepthMask(false);
9119         }
9120         else if(t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
9121         {
9122                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // can't do alpha test without texture, so let's blend instead
9123                 GL_DepthMask(false);
9124         }
9125         else if(t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
9126         {
9127                 GL_BlendFunc(t->customblendfunc[0], t->customblendfunc[1]);
9128                 GL_DepthMask(false);
9129         }
9130         else
9131         {
9132                 GL_BlendFunc(GL_ONE, GL_ZERO);
9133                 GL_DepthMask(writedepth);
9134         }
9135
9136         if (!r_refdef.view.showdebug)
9137         {
9138                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9139                 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices);
9140                 for (j = 0, vi = 0;j < rsurface.batchnumvertices;j++, vi++)
9141                 {
9142                         VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
9143                         Vector4Set(batchvertex[vi].color4f, 0, 0, 0, 1);
9144                 }
9145                 R_Mesh_PrepareVertices_Generic_Unlock();
9146                 RSurf_DrawBatch();
9147         }
9148         else if (r_showsurfaces.integer == 4)
9149         {
9150                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9151                 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices);
9152                 for (j = 0, vi = 0;j < rsurface.batchnumvertices;j++, vi++)
9153                 {
9154                         float d = (vi << 3) * (1.0f / 256.0f);
9155                         VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
9156                         Vector4Set(batchvertex[vi].color4f, d, d, d, 1);
9157                 }
9158                 R_Mesh_PrepareVertices_Generic_Unlock();
9159                 RSurf_DrawBatch();
9160         }
9161         else if (r_showsurfaces.integer == 2)
9162         {
9163                 const int *e;
9164                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9165                 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(3*rsurface.batchnumtriangles);
9166                 for (j = 0, e = rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle;j < rsurface.batchnumtriangles;j++, e += 3)
9167                 {
9168                         float d = ((j + rsurface.batchfirsttriangle) << 3) * (1.0f / 256.0f);
9169                         VectorCopy(rsurface.batchvertex3f + 3*e[0], batchvertex[j*3+0].vertex3f);
9170                         VectorCopy(rsurface.batchvertex3f + 3*e[1], batchvertex[j*3+1].vertex3f);
9171                         VectorCopy(rsurface.batchvertex3f + 3*e[2], batchvertex[j*3+2].vertex3f);
9172                         Vector4Set(batchvertex[j*3+0].color4f, d, d, d, 1);
9173                         Vector4Set(batchvertex[j*3+1].color4f, d, d, d, 1);
9174                         Vector4Set(batchvertex[j*3+2].color4f, d, d, d, 1);
9175                 }
9176                 R_Mesh_PrepareVertices_Generic_Unlock();
9177                 R_Mesh_Draw(0, rsurface.batchnumtriangles*3, 0, rsurface.batchnumtriangles, NULL, NULL, 0, NULL, NULL, 0);
9178         }
9179         else
9180         {
9181                 int texturesurfaceindex;
9182                 int k;
9183                 const msurface_t *surface;
9184                 float surfacecolor4f[4];
9185                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9186                 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchfirstvertex + rsurface.batchnumvertices);
9187                 vi = 0;
9188                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
9189                 {
9190                         surface = texturesurfacelist[texturesurfaceindex];
9191                         k = (int)(((size_t)surface) / sizeof(msurface_t));
9192                         Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
9193                         for (j = 0;j < surface->num_vertices;j++)
9194                         {
9195                                 VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
9196                                 Vector4Copy(surfacecolor4f, batchvertex[vi].color4f);
9197                                 vi++;
9198                         }
9199                 }
9200                 R_Mesh_PrepareVertices_Generic_Unlock();
9201                 RSurf_DrawBatch();
9202         }
9203 }
9204
9205 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
9206 {
9207         CHECKGLERROR
9208         RSurf_SetupDepthAndCulling();
9209         if (r_showsurfaces.integer)
9210         {
9211                 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
9212                 return;
9213         }
9214         switch (vid.renderpath)
9215         {
9216         case RENDERPATH_GL20:
9217         case RENDERPATH_GLES2:
9218                 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
9219                 break;
9220         }
9221         CHECKGLERROR
9222 }
9223
9224 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9225 {
9226         int i, j;
9227         int texturenumsurfaces, endsurface;
9228         texture_t *texture;
9229         const msurface_t *surface;
9230         const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
9231
9232         RSurf_ActiveModelEntity(ent, true, true, false);
9233
9234         if (r_transparentdepthmasking.integer)
9235         {
9236                 qboolean setup = false;
9237                 for (i = 0;i < numsurfaces;i = j)
9238                 {
9239                         j = i + 1;
9240                         surface = rsurface.modelsurfaces + surfacelist[i];
9241                         texture = surface->texture;
9242                         rsurface.texture = R_GetCurrentTexture(texture);
9243                         rsurface.lightmaptexture = NULL;
9244                         rsurface.deluxemaptexture = NULL;
9245                         rsurface.uselightmaptexture = false;
9246                         // scan ahead until we find a different texture
9247                         endsurface = min(i + 1024, numsurfaces);
9248                         texturenumsurfaces = 0;
9249                         texturesurfacelist[texturenumsurfaces++] = surface;
9250                         for (;j < endsurface;j++)
9251                         {
9252                                 surface = rsurface.modelsurfaces + surfacelist[j];
9253                                 if (texture != surface->texture)
9254                                         break;
9255                                 texturesurfacelist[texturenumsurfaces++] = surface;
9256                         }
9257                         if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
9258                                 continue;
9259                         // render the range of surfaces as depth
9260                         if (!setup)
9261                         {
9262                                 setup = true;
9263                                 GL_ColorMask(0,0,0,0);
9264                                 GL_Color(1,1,1,1);
9265                                 GL_DepthTest(true);
9266                                 GL_BlendFunc(GL_ONE, GL_ZERO);
9267                                 GL_DepthMask(true);
9268 //                              R_Mesh_ResetTextureState();
9269                         }
9270                         RSurf_SetupDepthAndCulling();
9271                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9272                         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9273                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9274                         RSurf_DrawBatch();
9275                 }
9276                 if (setup)
9277                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
9278         }
9279
9280         for (i = 0;i < numsurfaces;i = j)
9281         {
9282                 j = i + 1;
9283                 surface = rsurface.modelsurfaces + surfacelist[i];
9284                 texture = surface->texture;
9285                 rsurface.texture = R_GetCurrentTexture(texture);
9286                 // scan ahead until we find a different texture
9287                 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
9288                 texturenumsurfaces = 0;
9289                 texturesurfacelist[texturenumsurfaces++] = surface;
9290                 if(FAKELIGHT_ENABLED)
9291                 {
9292                         rsurface.lightmaptexture = NULL;
9293                         rsurface.deluxemaptexture = NULL;
9294                         rsurface.uselightmaptexture = false;
9295                         for (;j < endsurface;j++)
9296                         {
9297                                 surface = rsurface.modelsurfaces + surfacelist[j];
9298                                 if (texture != surface->texture)
9299                                         break;
9300                                 texturesurfacelist[texturenumsurfaces++] = surface;
9301                         }
9302                 }
9303                 else
9304                 {
9305                         rsurface.lightmaptexture = surface->lightmaptexture;
9306                         rsurface.deluxemaptexture = surface->deluxemaptexture;
9307                         rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
9308                         for (;j < endsurface;j++)
9309                         {
9310                                 surface = rsurface.modelsurfaces + surfacelist[j];
9311                                 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
9312                                         break;
9313                                 texturesurfacelist[texturenumsurfaces++] = surface;
9314                         }
9315                 }
9316                 // render the range of surfaces
9317                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false);
9318         }
9319         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
9320 }
9321
9322 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9323 {
9324         // transparent surfaces get pushed off into the transparent queue
9325         int surfacelistindex;
9326         const msurface_t *surface;
9327         vec3_t tempcenter, center;
9328         for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
9329         {
9330                 surface = texturesurfacelist[surfacelistindex];
9331                 if (r_transparent_sortsurfacesbynearest.integer)
9332                 {
9333                         tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
9334                         tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
9335                         tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
9336                 }
9337                 else
9338                 {
9339                         tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
9340                         tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
9341                         tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
9342                 }
9343                 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
9344                 if (rsurface.entity->transparent_offset) // transparent offset
9345                 {
9346                         center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
9347                         center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
9348                         center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
9349                 }
9350                 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);
9351         }
9352 }
9353
9354 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9355 {
9356         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
9357                 return;
9358         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
9359                 return;
9360         RSurf_SetupDepthAndCulling();
9361         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9362         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9363         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9364         RSurf_DrawBatch();
9365 }
9366
9367 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass)
9368 {
9369         CHECKGLERROR
9370         if (depthonly)
9371                 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
9372         else if (prepass)
9373         {
9374                 if (!rsurface.texture->currentnumlayers)
9375                         return;
9376                 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
9377                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9378                 else
9379                         R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
9380         }
9381         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
9382                 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
9383         else if (!rsurface.texture->currentnumlayers)
9384                 return;
9385         else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
9386         {
9387                 // in the deferred case, transparent surfaces were queued during prepass
9388                 if (!r_shadow_usingdeferredprepass)
9389                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9390         }
9391         else
9392         {
9393                 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
9394                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass);
9395         }
9396         CHECKGLERROR
9397 }
9398
9399 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass)
9400 {
9401         int i, j;
9402         texture_t *texture;
9403         R_FrameData_SetMark();
9404         // break the surface list down into batches by texture and use of lightmapping
9405         for (i = 0;i < numsurfaces;i = j)
9406         {
9407                 j = i + 1;
9408                 // texture is the base texture pointer, rsurface.texture is the
9409                 // current frame/skin the texture is directing us to use (for example
9410                 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
9411                 // use skin 1 instead)
9412                 texture = surfacelist[i]->texture;
9413                 rsurface.texture = R_GetCurrentTexture(texture);
9414                 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
9415                 {
9416                         // if this texture is not the kind we want, skip ahead to the next one
9417                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9418                                 ;
9419                         continue;
9420                 }
9421                 if(FAKELIGHT_ENABLED || depthonly || prepass)
9422                 {
9423                         rsurface.lightmaptexture = NULL;
9424                         rsurface.deluxemaptexture = NULL;
9425                         rsurface.uselightmaptexture = false;
9426                         // simply scan ahead until we find a different texture or lightmap state
9427                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9428                                 ;
9429                 }
9430                 else
9431                 {
9432                         rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
9433                         rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
9434                         rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
9435                         // simply scan ahead until we find a different texture or lightmap state
9436                         for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
9437                                 ;
9438                 }
9439                 // render the range of surfaces
9440                 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass);
9441         }
9442         R_FrameData_ReturnToMark();
9443 }
9444
9445 float locboxvertex3f[6*4*3] =
9446 {
9447         1,0,1, 1,0,0, 1,1,0, 1,1,1,
9448         0,1,1, 0,1,0, 0,0,0, 0,0,1,
9449         1,1,1, 1,1,0, 0,1,0, 0,1,1,
9450         0,0,1, 0,0,0, 1,0,0, 1,0,1,
9451         0,0,1, 1,0,1, 1,1,1, 0,1,1,
9452         1,0,0, 0,0,0, 0,1,0, 1,1,0
9453 };
9454
9455 unsigned short locboxelements[6*2*3] =
9456 {
9457          0, 1, 2, 0, 2, 3,
9458          4, 5, 6, 4, 6, 7,
9459          8, 9,10, 8,10,11,
9460         12,13,14, 12,14,15,
9461         16,17,18, 16,18,19,
9462         20,21,22, 20,22,23
9463 };
9464
9465 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9466 {
9467         int i, j;
9468         cl_locnode_t *loc = (cl_locnode_t *)ent;
9469         vec3_t mins, size;
9470         float vertex3f[6*4*3];
9471         CHECKGLERROR
9472         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9473         GL_DepthMask(false);
9474         GL_DepthRange(0, 1);
9475         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9476         GL_DepthTest(true);
9477         GL_CullFace(GL_NONE);
9478         R_EntityMatrix(&identitymatrix);
9479
9480 //      R_Mesh_ResetTextureState();
9481
9482         i = surfacelist[0];
9483         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9484                          ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9485                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9486                         surfacelist[0] < 0 ? 0.5f : 0.125f);
9487
9488         if (VectorCompare(loc->mins, loc->maxs))
9489         {
9490                 VectorSet(size, 2, 2, 2);
9491                 VectorMA(loc->mins, -0.5f, size, mins);
9492         }
9493         else
9494         {
9495                 VectorCopy(loc->mins, mins);
9496                 VectorSubtract(loc->maxs, loc->mins, size);
9497         }
9498
9499         for (i = 0;i < 6*4*3;)
9500                 for (j = 0;j < 3;j++, i++)
9501                         vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9502
9503         R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9504         R_SetupShader_Generic_NoTexture(false, false);
9505         R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9506 }
9507
9508 void R_DrawLocs(void)
9509 {
9510         int index;
9511         cl_locnode_t *loc, *nearestloc;
9512         vec3_t center;
9513         nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9514         for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9515         {
9516                 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9517                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9518         }
9519 }
9520
9521 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9522 {
9523         if (decalsystem->decals)
9524                 Mem_Free(decalsystem->decals);
9525         memset(decalsystem, 0, sizeof(*decalsystem));
9526 }
9527
9528 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)
9529 {
9530         tridecal_t *decal;
9531         tridecal_t *decals;
9532         int i;
9533
9534         // expand or initialize the system
9535         if (decalsystem->maxdecals <= decalsystem->numdecals)
9536         {
9537                 decalsystem_t old = *decalsystem;
9538                 qboolean useshortelements;
9539                 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9540                 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9541                 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)));
9542                 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9543                 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9544                 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9545                 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9546                 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9547                 if (decalsystem->numdecals)
9548                         memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9549                 if (old.decals)
9550                         Mem_Free(old.decals);
9551                 for (i = 0;i < decalsystem->maxdecals*3;i++)
9552                         decalsystem->element3i[i] = i;
9553                 if (useshortelements)
9554                         for (i = 0;i < decalsystem->maxdecals*3;i++)
9555                                 decalsystem->element3s[i] = i;
9556         }
9557
9558         // grab a decal and search for another free slot for the next one
9559         decals = decalsystem->decals;
9560         decal = decalsystem->decals + (i = decalsystem->freedecal++);
9561         for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9562                 ;
9563         decalsystem->freedecal = i;
9564         if (decalsystem->numdecals <= i)
9565                 decalsystem->numdecals = i + 1;
9566
9567         // initialize the decal
9568         decal->lived = 0;
9569         decal->triangleindex = triangleindex;
9570         decal->surfaceindex = surfaceindex;
9571         decal->decalsequence = decalsequence;
9572         decal->color4f[0][0] = c0[0];
9573         decal->color4f[0][1] = c0[1];
9574         decal->color4f[0][2] = c0[2];
9575         decal->color4f[0][3] = 1;
9576         decal->color4f[1][0] = c1[0];
9577         decal->color4f[1][1] = c1[1];
9578         decal->color4f[1][2] = c1[2];
9579         decal->color4f[1][3] = 1;
9580         decal->color4f[2][0] = c2[0];
9581         decal->color4f[2][1] = c2[1];
9582         decal->color4f[2][2] = c2[2];
9583         decal->color4f[2][3] = 1;
9584         decal->vertex3f[0][0] = v0[0];
9585         decal->vertex3f[0][1] = v0[1];
9586         decal->vertex3f[0][2] = v0[2];
9587         decal->vertex3f[1][0] = v1[0];
9588         decal->vertex3f[1][1] = v1[1];
9589         decal->vertex3f[1][2] = v1[2];
9590         decal->vertex3f[2][0] = v2[0];
9591         decal->vertex3f[2][1] = v2[1];
9592         decal->vertex3f[2][2] = v2[2];
9593         decal->texcoord2f[0][0] = t0[0];
9594         decal->texcoord2f[0][1] = t0[1];
9595         decal->texcoord2f[1][0] = t1[0];
9596         decal->texcoord2f[1][1] = t1[1];
9597         decal->texcoord2f[2][0] = t2[0];
9598         decal->texcoord2f[2][1] = t2[1];
9599         TriangleNormal(v0, v1, v2, decal->plane);
9600         VectorNormalize(decal->plane);
9601         decal->plane[3] = DotProduct(v0, decal->plane);
9602 }
9603
9604 extern cvar_t cl_decals_bias;
9605 extern cvar_t cl_decals_models;
9606 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9607 // baseparms, parms, temps
9608 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)
9609 {
9610         int cornerindex;
9611         int index;
9612         float v[9][3];
9613         const float *vertex3f;
9614         const float *normal3f;
9615         int numpoints;
9616         float points[2][9][3];
9617         float temp[3];
9618         float tc[9][2];
9619         float f;
9620         float c[9][4];
9621         const int *e;
9622
9623         e = rsurface.modelelement3i + 3*triangleindex;
9624
9625         vertex3f = rsurface.modelvertex3f;
9626         normal3f = rsurface.modelnormal3f;
9627
9628         if (normal3f)
9629         {
9630                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9631                 {
9632                         index = 3*e[cornerindex];
9633                         VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9634                 }
9635         }
9636         else
9637         {
9638                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9639                 {
9640                         index = 3*e[cornerindex];
9641                         VectorCopy(vertex3f + index, v[cornerindex]);
9642                 }
9643         }
9644
9645         // cull backfaces
9646         //TriangleNormal(v[0], v[1], v[2], normal);
9647         //if (DotProduct(normal, localnormal) < 0.0f)
9648         //      continue;
9649         // clip by each of the box planes formed from the projection matrix
9650         // if anything survives, we emit the decal
9651         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]);
9652         if (numpoints < 3)
9653                 return;
9654         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]);
9655         if (numpoints < 3)
9656                 return;
9657         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]);
9658         if (numpoints < 3)
9659                 return;
9660         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]);
9661         if (numpoints < 3)
9662                 return;
9663         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]);
9664         if (numpoints < 3)
9665                 return;
9666         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]);
9667         if (numpoints < 3)
9668                 return;
9669         // some part of the triangle survived, so we have to accept it...
9670         if (dynamic)
9671         {
9672                 // dynamic always uses the original triangle
9673                 numpoints = 3;
9674                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9675                 {
9676                         index = 3*e[cornerindex];
9677                         VectorCopy(vertex3f + index, v[cornerindex]);
9678                 }
9679         }
9680         for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9681         {
9682                 // convert vertex positions to texcoords
9683                 Matrix4x4_Transform(projection, v[cornerindex], temp);
9684                 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9685                 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9686                 // calculate distance fade from the projection origin
9687                 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9688                 f = bound(0.0f, f, 1.0f);
9689                 c[cornerindex][0] = r * f;
9690                 c[cornerindex][1] = g * f;
9691                 c[cornerindex][2] = b * f;
9692                 c[cornerindex][3] = 1.0f;
9693                 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9694         }
9695         if (dynamic)
9696                 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);
9697         else
9698                 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9699                         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);
9700 }
9701 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)
9702 {
9703         matrix4x4_t projection;
9704         decalsystem_t *decalsystem;
9705         qboolean dynamic;
9706         dp_model_t *model;
9707         const msurface_t *surface;
9708         const msurface_t *surfaces;
9709         const int *surfacelist;
9710         const texture_t *texture;
9711         int numtriangles;
9712         int numsurfacelist;
9713         int surfacelistindex;
9714         int surfaceindex;
9715         int triangleindex;
9716         float localorigin[3];
9717         float localnormal[3];
9718         float localmins[3];
9719         float localmaxs[3];
9720         float localsize;
9721         //float normal[3];
9722         float planes[6][4];
9723         float angles[3];
9724         bih_t *bih;
9725         int bih_triangles_count;
9726         int bih_triangles[256];
9727         int bih_surfaces[256];
9728
9729         decalsystem = &ent->decalsystem;
9730         model = ent->model;
9731         if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9732         {
9733                 R_DecalSystem_Reset(&ent->decalsystem);
9734                 return;
9735         }
9736
9737         if (!model->brush.data_leafs && !cl_decals_models.integer)
9738         {
9739                 if (decalsystem->model)
9740                         R_DecalSystem_Reset(decalsystem);
9741                 return;
9742         }
9743
9744         if (decalsystem->model != model)
9745                 R_DecalSystem_Reset(decalsystem);
9746         decalsystem->model = model;
9747
9748         RSurf_ActiveModelEntity(ent, true, false, false);
9749
9750         Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9751         Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9752         VectorNormalize(localnormal);
9753         localsize = worldsize*rsurface.inversematrixscale;
9754         localmins[0] = localorigin[0] - localsize;
9755         localmins[1] = localorigin[1] - localsize;
9756         localmins[2] = localorigin[2] - localsize;
9757         localmaxs[0] = localorigin[0] + localsize;
9758         localmaxs[1] = localorigin[1] + localsize;
9759         localmaxs[2] = localorigin[2] + localsize;
9760
9761         //VectorCopy(localnormal, planes[4]);
9762         //VectorVectors(planes[4], planes[2], planes[0]);
9763         AnglesFromVectors(angles, localnormal, NULL, false);
9764         AngleVectors(angles, planes[0], planes[2], planes[4]);
9765         VectorNegate(planes[0], planes[1]);
9766         VectorNegate(planes[2], planes[3]);
9767         VectorNegate(planes[4], planes[5]);
9768         planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9769         planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9770         planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9771         planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9772         planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9773         planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9774
9775 #if 1
9776 // works
9777 {
9778         matrix4x4_t forwardprojection;
9779         Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9780         Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9781 }
9782 #else
9783 // broken
9784 {
9785         float projectionvector[4][3];
9786         VectorScale(planes[0], ilocalsize, projectionvector[0]);
9787         VectorScale(planes[2], ilocalsize, projectionvector[1]);
9788         VectorScale(planes[4], ilocalsize, projectionvector[2]);
9789         projectionvector[0][0] = planes[0][0] * ilocalsize;
9790         projectionvector[0][1] = planes[1][0] * ilocalsize;
9791         projectionvector[0][2] = planes[2][0] * ilocalsize;
9792         projectionvector[1][0] = planes[0][1] * ilocalsize;
9793         projectionvector[1][1] = planes[1][1] * ilocalsize;
9794         projectionvector[1][2] = planes[2][1] * ilocalsize;
9795         projectionvector[2][0] = planes[0][2] * ilocalsize;
9796         projectionvector[2][1] = planes[1][2] * ilocalsize;
9797         projectionvector[2][2] = planes[2][2] * ilocalsize;
9798         projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9799         projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9800         projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9801         Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9802 }
9803 #endif
9804
9805         dynamic = model->surfmesh.isanimated;
9806         numsurfacelist = model->nummodelsurfaces;
9807         surfacelist = model->sortedmodelsurfaces;
9808         surfaces = model->data_surfaces;
9809
9810         bih = NULL;
9811         bih_triangles_count = -1;
9812         if(!dynamic)
9813         {
9814                 if(model->render_bih.numleafs)
9815                         bih = &model->render_bih;
9816                 else if(model->collision_bih.numleafs)
9817                         bih = &model->collision_bih;
9818         }
9819         if(bih)
9820                 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9821         if(bih_triangles_count == 0)
9822                 return;
9823         if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9824                 return;
9825         if(bih_triangles_count > 0)
9826         {
9827                 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9828                 {
9829                         surfaceindex = bih_surfaces[triangleindex];
9830                         surface = surfaces + surfaceindex;
9831                         texture = surface->texture;
9832                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9833                                 continue;
9834                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9835                                 continue;
9836                         R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9837                 }
9838         }
9839         else
9840         {
9841                 for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
9842                 {
9843                         surfaceindex = surfacelist[surfacelistindex];
9844                         surface = surfaces + surfaceindex;
9845                         // check cull box first because it rejects more than any other check
9846                         if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9847                                 continue;
9848                         // skip transparent surfaces
9849                         texture = surface->texture;
9850                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9851                                 continue;
9852                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9853                                 continue;
9854                         numtriangles = surface->num_triangles;
9855                         for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9856                                 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9857                 }
9858         }
9859 }
9860
9861 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9862 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)
9863 {
9864         int renderentityindex;
9865         float worldmins[3];
9866         float worldmaxs[3];
9867         entity_render_t *ent;
9868
9869         if (!cl_decals_newsystem.integer)
9870                 return;
9871
9872         worldmins[0] = worldorigin[0] - worldsize;
9873         worldmins[1] = worldorigin[1] - worldsize;
9874         worldmins[2] = worldorigin[2] - worldsize;
9875         worldmaxs[0] = worldorigin[0] + worldsize;
9876         worldmaxs[1] = worldorigin[1] + worldsize;
9877         worldmaxs[2] = worldorigin[2] + worldsize;
9878
9879         R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9880
9881         for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9882         {
9883                 ent = r_refdef.scene.entities[renderentityindex];
9884                 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9885                         continue;
9886
9887                 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9888         }
9889 }
9890
9891 typedef struct r_decalsystem_splatqueue_s
9892 {
9893         vec3_t worldorigin;
9894         vec3_t worldnormal;
9895         float color[4];
9896         float tcrange[4];
9897         float worldsize;
9898         unsigned int decalsequence;
9899 }
9900 r_decalsystem_splatqueue_t;
9901
9902 int r_decalsystem_numqueued = 0;
9903 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9904
9905 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)
9906 {
9907         r_decalsystem_splatqueue_t *queue;
9908
9909         if (!cl_decals_newsystem.integer || r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9910                 return;
9911
9912         queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9913         VectorCopy(worldorigin, queue->worldorigin);
9914         VectorCopy(worldnormal, queue->worldnormal);
9915         Vector4Set(queue->color, r, g, b, a);
9916         Vector4Set(queue->tcrange, s1, t1, s2, t2);
9917         queue->worldsize = worldsize;
9918         queue->decalsequence = cl.decalsequence++;
9919 }
9920
9921 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9922 {
9923         int i;
9924         r_decalsystem_splatqueue_t *queue;
9925
9926         for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9927                 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);
9928         r_decalsystem_numqueued = 0;
9929 }
9930
9931 extern cvar_t cl_decals_max;
9932 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9933 {
9934         int i;
9935         decalsystem_t *decalsystem = &ent->decalsystem;
9936         int numdecals;
9937         unsigned int killsequence;
9938         tridecal_t *decal;
9939         float frametime;
9940         float lifetime;
9941
9942         if (!decalsystem->numdecals)
9943                 return;
9944
9945         if (r_showsurfaces.integer)
9946                 return;
9947
9948         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9949         {
9950                 R_DecalSystem_Reset(decalsystem);
9951                 return;
9952         }
9953
9954         killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9955         lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9956
9957         if (decalsystem->lastupdatetime)
9958                 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9959         else
9960                 frametime = 0;
9961         decalsystem->lastupdatetime = r_refdef.scene.time;
9962         numdecals = decalsystem->numdecals;
9963
9964         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9965         {
9966                 if (decal->color4f[0][3])
9967                 {
9968                         decal->lived += frametime;
9969                         if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9970                         {
9971                                 memset(decal, 0, sizeof(*decal));
9972                                 if (decalsystem->freedecal > i)
9973                                         decalsystem->freedecal = i;
9974                         }
9975                 }
9976         }
9977         decal = decalsystem->decals;
9978         while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9979                 numdecals--;
9980
9981         // collapse the array by shuffling the tail decals into the gaps
9982         for (;;)
9983         {
9984                 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
9985                         decalsystem->freedecal++;
9986                 if (decalsystem->freedecal == numdecals)
9987                         break;
9988                 decal[decalsystem->freedecal] = decal[--numdecals];
9989         }
9990
9991         decalsystem->numdecals = numdecals;
9992
9993         if (numdecals <= 0)
9994         {
9995                 // if there are no decals left, reset decalsystem
9996                 R_DecalSystem_Reset(decalsystem);
9997         }
9998 }
9999
10000 extern skinframe_t *decalskinframe;
10001 static void R_DrawModelDecals_Entity(entity_render_t *ent)
10002 {
10003         int i;
10004         decalsystem_t *decalsystem = &ent->decalsystem;
10005         int numdecals;
10006         tridecal_t *decal;
10007         float faderate;
10008         float alpha;
10009         float *v3f;
10010         float *c4f;
10011         float *t2f;
10012         const int *e;
10013         const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
10014         int numtris = 0;
10015
10016         numdecals = decalsystem->numdecals;
10017         if (!numdecals)
10018                 return;
10019
10020         if (r_showsurfaces.integer)
10021                 return;
10022
10023         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
10024         {
10025                 R_DecalSystem_Reset(decalsystem);
10026                 return;
10027         }
10028
10029         // if the model is static it doesn't matter what value we give for
10030         // wantnormals and wanttangents, so this logic uses only rules applicable
10031         // to a model, knowing that they are meaningless otherwise
10032         RSurf_ActiveModelEntity(ent, false, false, false);
10033
10034         decalsystem->lastupdatetime = r_refdef.scene.time;
10035
10036         faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
10037
10038         // update vertex positions for animated models
10039         v3f = decalsystem->vertex3f;
10040         c4f = decalsystem->color4f;
10041         t2f = decalsystem->texcoord2f;
10042         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
10043         {
10044                 if (!decal->color4f[0][3])
10045                         continue;
10046
10047                 if (surfacevisible && !surfacevisible[decal->surfaceindex])
10048                         continue;
10049
10050                 // skip backfaces
10051                 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
10052                         continue;
10053
10054                 // update color values for fading decals
10055                 if (decal->lived >= cl_decals_time.value)
10056                         alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
10057                 else
10058                         alpha = 1.0f;
10059
10060                 c4f[ 0] = decal->color4f[0][0] * alpha;
10061                 c4f[ 1] = decal->color4f[0][1] * alpha;
10062                 c4f[ 2] = decal->color4f[0][2] * alpha;
10063                 c4f[ 3] = 1;
10064                 c4f[ 4] = decal->color4f[1][0] * alpha;
10065                 c4f[ 5] = decal->color4f[1][1] * alpha;
10066                 c4f[ 6] = decal->color4f[1][2] * alpha;
10067                 c4f[ 7] = 1;
10068                 c4f[ 8] = decal->color4f[2][0] * alpha;
10069                 c4f[ 9] = decal->color4f[2][1] * alpha;
10070                 c4f[10] = decal->color4f[2][2] * alpha;
10071                 c4f[11] = 1;
10072
10073                 t2f[0] = decal->texcoord2f[0][0];
10074                 t2f[1] = decal->texcoord2f[0][1];
10075                 t2f[2] = decal->texcoord2f[1][0];
10076                 t2f[3] = decal->texcoord2f[1][1];
10077                 t2f[4] = decal->texcoord2f[2][0];
10078                 t2f[5] = decal->texcoord2f[2][1];
10079
10080                 // update vertex positions for animated models
10081                 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
10082                 {
10083                         e = rsurface.modelelement3i + 3*decal->triangleindex;
10084                         VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
10085                         VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
10086                         VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
10087                 }
10088                 else
10089                 {
10090                         VectorCopy(decal->vertex3f[0], v3f);
10091                         VectorCopy(decal->vertex3f[1], v3f + 3);
10092                         VectorCopy(decal->vertex3f[2], v3f + 6);
10093                 }
10094
10095                 if (r_refdef.fogenabled)
10096                 {
10097                         alpha = RSurf_FogVertex(v3f);
10098                         VectorScale(c4f, alpha, c4f);
10099                         alpha = RSurf_FogVertex(v3f + 3);
10100                         VectorScale(c4f + 4, alpha, c4f + 4);
10101                         alpha = RSurf_FogVertex(v3f + 6);
10102                         VectorScale(c4f + 8, alpha, c4f + 8);
10103                 }
10104
10105                 v3f += 9;
10106                 c4f += 12;
10107                 t2f += 6;
10108                 numtris++;
10109         }
10110
10111         if (numtris > 0)
10112         {
10113                 r_refdef.stats[r_stat_drawndecals] += numtris;
10114
10115                 // now render the decals all at once
10116                 // (this assumes they all use one particle font texture!)
10117                 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);
10118 //              R_Mesh_ResetTextureState();
10119                 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
10120                 GL_DepthMask(false);
10121                 GL_DepthRange(0, 1);
10122                 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
10123                 GL_DepthTest(true);
10124                 GL_CullFace(GL_NONE);
10125                 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
10126                 R_SetupShader_Generic(decalskinframe->base, NULL, GL_MODULATE, 1, false, false, false);
10127                 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
10128         }
10129 }
10130
10131 static void R_DrawModelDecals(void)
10132 {
10133         int i, numdecals;
10134
10135         // fade faster when there are too many decals
10136         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
10137         for (i = 0;i < r_refdef.scene.numentities;i++)
10138                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
10139
10140         R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
10141         for (i = 0;i < r_refdef.scene.numentities;i++)
10142                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
10143                         R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
10144
10145         R_DecalSystem_ApplySplatEntitiesQueue();
10146
10147         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
10148         for (i = 0;i < r_refdef.scene.numentities;i++)
10149                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
10150
10151         r_refdef.stats[r_stat_totaldecals] += numdecals;
10152
10153         if (r_showsurfaces.integer)
10154                 return;
10155
10156         R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
10157
10158         for (i = 0;i < r_refdef.scene.numentities;i++)
10159         {
10160                 if (!r_refdef.viewcache.entityvisible[i])
10161                         continue;
10162                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
10163                         R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
10164         }
10165 }
10166
10167 extern cvar_t mod_collision_bih;
10168 static void R_DrawDebugModel(void)
10169 {
10170         entity_render_t *ent = rsurface.entity;
10171         int i, j, flagsmask;
10172         const msurface_t *surface;
10173         dp_model_t *model = ent->model;
10174
10175         if (!sv.active  && !cls.demoplayback && ent != r_refdef.scene.worldentity)
10176                 return;
10177
10178         if (r_showoverdraw.value > 0)
10179         {
10180                 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
10181                 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
10182                 R_SetupShader_Generic_NoTexture(false, false);
10183                 GL_DepthTest(false);
10184                 GL_DepthMask(false);
10185                 GL_DepthRange(0, 1);
10186                 GL_BlendFunc(GL_ONE, GL_ONE);
10187                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10188                 {
10189                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10190                                 continue;
10191                         rsurface.texture = R_GetCurrentTexture(surface->texture);
10192                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10193                         {
10194                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
10195                                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
10196                                 if (!rsurface.texture->currentlayers->depthmask)
10197                                         GL_Color(c, 0, 0, 1.0f);
10198                                 else if (ent == r_refdef.scene.worldentity)
10199                                         GL_Color(c, c, c, 1.0f);
10200                                 else
10201                                         GL_Color(0, c, 0, 1.0f);
10202                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
10203                                 RSurf_DrawBatch();
10204                         }
10205                 }
10206                 rsurface.texture = NULL;
10207         }
10208
10209         flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
10210
10211 //      R_Mesh_ResetTextureState();
10212         R_SetupShader_Generic_NoTexture(false, false);
10213         GL_DepthRange(0, 1);
10214         GL_DepthTest(!r_showdisabledepthtest.integer);
10215         GL_DepthMask(false);
10216         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10217
10218         if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
10219         {
10220                 int triangleindex;
10221                 int bihleafindex;
10222                 qboolean cullbox = false;
10223                 const q3mbrush_t *brush;
10224                 const bih_t *bih = &model->collision_bih;
10225                 const bih_leaf_t *bihleaf;
10226                 float vertex3f[3][3];
10227                 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
10228                 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
10229                 {
10230                         if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
10231                                 continue;
10232                         switch (bihleaf->type)
10233                         {
10234                         case BIH_BRUSH:
10235                                 brush = model->brush.data_brushes + bihleaf->itemindex;
10236                                 if (brush->colbrushf && brush->colbrushf->numtriangles)
10237                                 {
10238                                         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);
10239                                         R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
10240                                         R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
10241                                 }
10242                                 break;
10243                         case BIH_COLLISIONTRIANGLE:
10244                                 triangleindex = bihleaf->itemindex;
10245                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
10246                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
10247                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
10248                                 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);
10249                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
10250                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
10251                                 break;
10252                         case BIH_RENDERTRIANGLE:
10253                                 triangleindex = bihleaf->itemindex;
10254                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
10255                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
10256                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
10257                                 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);
10258                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
10259                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
10260                                 break;
10261                         }
10262                 }
10263         }
10264
10265         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
10266
10267 #ifndef USE_GLES2
10268         if (r_showtris.value > 0 && qglPolygonMode)
10269         {
10270                 if (r_showdisabledepthtest.integer)
10271                 {
10272                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10273                         GL_DepthMask(false);
10274                 }
10275                 else
10276                 {
10277                         GL_BlendFunc(GL_ONE, GL_ZERO);
10278                         GL_DepthMask(true);
10279                 }
10280                 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
10281                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10282                 {
10283                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10284                                 continue;
10285                         rsurface.texture = R_GetCurrentTexture(surface->texture);
10286                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10287                         {
10288                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
10289                                 if (!rsurface.texture->currentlayers->depthmask)
10290                                         GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
10291                                 else if (ent == r_refdef.scene.worldentity)
10292                                         GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
10293                                 else
10294                                         GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
10295                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
10296                                 RSurf_DrawBatch();
10297                         }
10298                 }
10299                 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
10300                 rsurface.texture = NULL;
10301         }
10302
10303 # if 0
10304         // FIXME!  implement r_shownormals with just triangles
10305         if (r_shownormals.value != 0 && qglBegin)
10306         {
10307                 int l, k;
10308                 vec3_t v;
10309                 if (r_showdisabledepthtest.integer)
10310                 {
10311                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10312                         GL_DepthMask(false);
10313                 }
10314                 else
10315                 {
10316                         GL_BlendFunc(GL_ONE, GL_ZERO);
10317                         GL_DepthMask(true);
10318                 }
10319                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10320                 {
10321                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10322                                 continue;
10323                         rsurface.texture = R_GetCurrentTexture(surface->texture);
10324                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10325                         {
10326                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
10327                                 qglBegin(GL_LINES);
10328                                 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
10329                                 {
10330                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10331                                         {
10332                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10333                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10334                                                 qglVertex3f(v[0], v[1], v[2]);
10335                                                 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10336                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10337                                                 qglVertex3f(v[0], v[1], v[2]);
10338                                         }
10339                                 }
10340                                 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
10341                                 {
10342                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10343                                         {
10344                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10345                                                 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
10346                                                 qglVertex3f(v[0], v[1], v[2]);
10347                                                 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
10348                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10349                                                 qglVertex3f(v[0], v[1], v[2]);
10350                                         }
10351                                 }
10352                                 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
10353                                 {
10354                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10355                                         {
10356                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10357                                                 GL_Color(0, r_refdef.view.colorscale, 0, 1);
10358                                                 qglVertex3f(v[0], v[1], v[2]);
10359                                                 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
10360                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10361                                                 qglVertex3f(v[0], v[1], v[2]);
10362                                         }
10363                                 }
10364                                 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
10365                                 {
10366                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10367                                         {
10368                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10369                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10370                                                 qglVertex3f(v[0], v[1], v[2]);
10371                                                 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10372                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10373                                                 qglVertex3f(v[0], v[1], v[2]);
10374                                         }
10375                                 }
10376                                 qglEnd();
10377                                 CHECKGLERROR
10378                         }
10379                 }
10380                 rsurface.texture = NULL;
10381         }
10382 # endif
10383 #endif
10384 }
10385
10386 int r_maxsurfacelist = 0;
10387 const msurface_t **r_surfacelist = NULL;
10388 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass)
10389 {
10390         int i, j, endj, flagsmask;
10391         dp_model_t *model = ent->model;
10392         msurface_t *surfaces;
10393         unsigned char *update;
10394         int numsurfacelist = 0;
10395         if (model == NULL)
10396                 return;
10397
10398         if (r_maxsurfacelist < model->num_surfaces)
10399         {
10400                 r_maxsurfacelist = model->num_surfaces;
10401                 if (r_surfacelist)
10402                         Mem_Free((msurface_t **)r_surfacelist);
10403                 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
10404         }
10405
10406         if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
10407                 RSurf_ActiveModelEntity(ent, false, false, false);
10408         else if (prepass)
10409                 RSurf_ActiveModelEntity(ent, true, true, true);
10410         else if (depthonly)
10411                 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
10412         else
10413                 RSurf_ActiveModelEntity(ent, true, true, false);
10414
10415         surfaces = model->data_surfaces;
10416         update = model->brushq1.lightmapupdateflags;
10417
10418         // update light styles
10419         if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0)
10420         {
10421                 model_brush_lightstyleinfo_t *style;
10422                 for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
10423                 {
10424                         if (style->value != r_refdef.scene.lightstylevalue[style->style])
10425                         {
10426                                 int *list = style->surfacelist;
10427                                 style->value = r_refdef.scene.lightstylevalue[style->style];
10428                                 for (j = 0;j < style->numsurfaces;j++)
10429                                         update[list[j]] = true;
10430                         }
10431                 }
10432         }
10433
10434         flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
10435
10436         if (debug)
10437         {
10438                 R_DrawDebugModel();
10439                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10440                 return;
10441         }
10442
10443         rsurface.lightmaptexture = NULL;
10444         rsurface.deluxemaptexture = NULL;
10445         rsurface.uselightmaptexture = false;
10446         rsurface.texture = NULL;
10447         rsurface.rtlight = NULL;
10448         numsurfacelist = 0;
10449         // add visible surfaces to draw list
10450         if (ent == r_refdef.scene.worldentity)
10451         {
10452                 // for the world entity, check surfacevisible
10453                 for (i = 0;i < model->nummodelsurfaces;i++)
10454                 {
10455                         j = model->sortedmodelsurfaces[i];
10456                         if (r_refdef.viewcache.world_surfacevisible[j])
10457                                 r_surfacelist[numsurfacelist++] = surfaces + j;
10458                 }
10459         }
10460         else
10461         {
10462                 // add all surfaces
10463                 for (i = 0; i < model->nummodelsurfaces; i++)
10464                         r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
10465         }
10466         // don't do anything if there were no surfaces
10467         if (!numsurfacelist)
10468         {
10469                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10470                 return;
10471         }
10472         // update lightmaps if needed
10473         if (update)
10474         {
10475                 int updated = 0;
10476                 for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
10477                 {
10478                         if (update[j])
10479                         {
10480                                 updated++;
10481                                 R_BuildLightMap(ent, surfaces + j);
10482                         }
10483                 }
10484         }
10485
10486         R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass);
10487
10488         // add to stats if desired
10489         if (r_speeds.integer && !skysurfaces && !depthonly)
10490         {
10491                 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10492                 for (j = 0;j < numsurfacelist;j++)
10493                         r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10494         }
10495
10496         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10497 }
10498
10499 void R_DebugLine(vec3_t start, vec3_t end)
10500 {
10501         dp_model_t *mod = CL_Mesh_UI();
10502         msurface_t *surf;
10503         int e0, e1, e2, e3;
10504         float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10505         float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10506         float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10507         vec4_t w[2], s[2];
10508
10509         // transform to screen coords first
10510         Vector4Set(w[0], start[0], start[1], start[2], 1);
10511         Vector4Set(w[1], end[0], end[1], end[2], 1);
10512         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10513         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10514         x1 = s[0][0] * vid_conwidth.value / vid.width;
10515         y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10516         x2 = s[1][0] * vid_conwidth.value / vid.width;
10517         y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10518         //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10519
10520         // add the line to the UI mesh for drawing later
10521
10522         // width is measured in real pixels
10523         if (fabs(x2 - x1) > fabs(y2 - y1))
10524         {
10525                 offsetx = 0;
10526                 offsety = 0.5f * width * vid_conheight.value / vid.height;
10527         }
10528         else
10529         {
10530                 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10531                 offsety = 0;
10532         }
10533         surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_VERTEXCOLOR), true);
10534         e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10535         e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10536         e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10537         e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10538         Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10539         Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10540
10541 }
10542
10543
10544 void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass)
10545 {
10546         int q;
10547         static texture_t texture;
10548         static msurface_t surface;
10549         const msurface_t *surfacelist = &surface;
10550
10551         // fake enough texture and surface state to render this geometry
10552
10553         texture.update_lastrenderframe = -1; // regenerate this texture
10554         texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10555         texture.basealpha = 1.0f;
10556         texture.currentskinframe = skinframe;
10557         texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10558         texture.offsetmapping = OFFSETMAPPING_OFF;
10559         texture.offsetscale = 1;
10560         texture.specularscalemod = 1;
10561         texture.specularpowermod = 1;
10562         texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10563         // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
10564         // JUST GREP FOR "specularscalemod = 1".
10565
10566         for (q = 0; q < 3; q++)
10567         {
10568                 texture.render_glowmod[q] = r_refdef.view.colorscale * r_hdr_glowintensity.value;
10569                 texture.render_modellight_lightdir[q] = q == 2;
10570                 texture.render_modellight_ambient[q] = r_refdef.view.colorscale * r_refdef.scene.ambientintensity;
10571                 texture.render_modellight_diffuse[q] = r_refdef.view.colorscale;
10572                 texture.render_modellight_specular[q] = r_refdef.view.colorscale;
10573                 texture.render_lightmap_ambient[q] = r_refdef.view.colorscale * r_refdef.scene.ambientintensity;
10574                 texture.render_lightmap_diffuse[q] = r_refdef.view.colorscale * r_refdef.scene.lightmapintensity;
10575                 texture.render_lightmap_specular[q] = r_refdef.view.colorscale;
10576                 texture.render_rtlight_diffuse[q] = r_refdef.view.colorscale;
10577                 texture.render_rtlight_specular[q] = r_refdef.view.colorscale;
10578         }
10579         texture.currentalpha = 1.0f;
10580
10581         surface.texture = &texture;
10582         surface.num_triangles = numtriangles;
10583         surface.num_firsttriangle = firsttriangle;
10584         surface.num_vertices = numvertices;
10585         surface.num_firstvertex = firstvertex;
10586
10587         // now render it
10588         rsurface.texture = R_GetCurrentTexture(surface.texture);
10589         rsurface.lightmaptexture = NULL;
10590         rsurface.deluxemaptexture = NULL;
10591         rsurface.uselightmaptexture = false;
10592         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);
10593 }
10594
10595 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)
10596 {
10597         static msurface_t surface;
10598         const msurface_t *surfacelist = &surface;
10599
10600         // fake enough texture and surface state to render this geometry
10601         surface.texture = texture;
10602         surface.num_triangles = numtriangles;
10603         surface.num_firsttriangle = firsttriangle;
10604         surface.num_vertices = numvertices;
10605         surface.num_firstvertex = firstvertex;
10606
10607         // now render it
10608         rsurface.texture = R_GetCurrentTexture(surface.texture);
10609         rsurface.lightmaptexture = NULL;
10610         rsurface.deluxemaptexture = NULL;
10611         rsurface.uselightmaptexture = false;
10612         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);
10613 }