]> git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
Remove some unused parameters on R_SetupShader_Generic.
[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 *t, 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 (t)
1480                 permutation |= SHADERPERMUTATION_DIFFUSE;
1481         if (usegamma && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
1482                 permutation |= SHADERPERMUTATION_GAMMARAMPS;
1483         if (suppresstexalpha)
1484                 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1485         if (vid.allowalphatocoverage)
1486                 GL_AlphaToCoverage(false);
1487         switch (vid.renderpath)
1488         {
1489         case RENDERPATH_GL20:
1490         case RENDERPATH_GLES2:
1491                 R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation);
1492                 if (r_glsl_permutation->tex_Texture_First >= 0)
1493                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First, t);
1494                 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0)
1495                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps);
1496                 break;
1497         }
1498 }
1499
1500 void R_SetupShader_Generic_NoTexture(qboolean usegamma, qboolean notrippy)
1501 {
1502         R_SetupShader_Generic(NULL, usegamma, notrippy, false);
1503 }
1504
1505 void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb, qboolean skeletal)
1506 {
1507         dpuint64 permutation = 0;
1508         if (r_trippy.integer && !notrippy)
1509                 permutation |= SHADERPERMUTATION_TRIPPY;
1510         if (depthrgb)
1511                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1512         if (skeletal)
1513                 permutation |= SHADERPERMUTATION_SKELETAL;
1514
1515         if (vid.allowalphatocoverage)
1516                 GL_AlphaToCoverage(false);
1517         switch (vid.renderpath)
1518         {
1519         case RENDERPATH_GL20:
1520         case RENDERPATH_GLES2:
1521                 R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
1522 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1523                 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);
1524 #endif
1525                 break;
1526         }
1527 }
1528
1529 #define BLENDFUNC_ALLOWS_COLORMOD      1
1530 #define BLENDFUNC_ALLOWS_FOG           2
1531 #define BLENDFUNC_ALLOWS_FOG_HACK0     4
1532 #define BLENDFUNC_ALLOWS_FOG_HACKALPHA 8
1533 #define BLENDFUNC_ALLOWS_ANYFOG        (BLENDFUNC_ALLOWS_FOG | BLENDFUNC_ALLOWS_FOG_HACK0 | BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1534 static int R_BlendFuncFlags(int src, int dst)
1535 {
1536         int r = 0;
1537
1538         // a blendfunc allows colormod if:
1539         // a) it can never keep the destination pixel invariant, or
1540         // b) it can keep the destination pixel invariant, and still can do so if colormodded
1541         // this is to prevent unintended side effects from colormod
1542
1543         // a blendfunc allows fog if:
1544         // blend(fog(src), fog(dst)) == fog(blend(src, dst))
1545         // this is to prevent unintended side effects from fog
1546
1547         // these checks are the output of fogeval.pl
1548
1549         r |= BLENDFUNC_ALLOWS_COLORMOD;
1550         if(src == GL_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1551         if(src == GL_DST_ALPHA && dst == GL_ONE_MINUS_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1552         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1553         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1554         if(src == GL_DST_COLOR && dst == GL_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1555         if(src == GL_DST_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1556         if(src == GL_DST_COLOR && dst == GL_ZERO) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1557         if(src == GL_ONE && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1558         if(src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG_HACKALPHA;
1559         if(src == GL_ONE && dst == GL_ZERO) r |= BLENDFUNC_ALLOWS_FOG;
1560         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1561         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1562         if(src == GL_ONE_MINUS_DST_COLOR && dst == GL_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1563         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1564         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1565         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1566         if(src == GL_ONE_MINUS_SRC_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1567         if(src == GL_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1568         if(src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1569         if(src == GL_ZERO && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG;
1570         if(src == GL_ZERO && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1571
1572         return r;
1573 }
1574
1575 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)
1576 {
1577         // select a permutation of the lighting shader appropriate to this
1578         // combination of texture, entity, light source, and fogging, only use the
1579         // minimum features necessary to avoid wasting rendering time in the
1580         // fragment shader on features that are not being used
1581         dpuint64 permutation = 0;
1582         unsigned int mode = 0;
1583         int blendfuncflags;
1584         texture_t *t = rsurface.texture;
1585         float m16f[16];
1586         matrix4x4_t tempmatrix;
1587         r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
1588         if (r_trippy.integer && !notrippy)
1589                 permutation |= SHADERPERMUTATION_TRIPPY;
1590         if (t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1591                 permutation |= SHADERPERMUTATION_ALPHAKILL;
1592         if (t->currentmaterialflags & MATERIALFLAG_OCCLUDE)
1593                 permutation |= SHADERPERMUTATION_OCCLUDE;
1594         if (t->r_water_waterscroll[0] && t->r_water_waterscroll[1])
1595                 permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
1596         if (rsurfacepass == RSURFPASS_BACKGROUND)
1597         {
1598                 // distorted background
1599                 if (t->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1600                 {
1601                         mode = SHADERMODE_WATER;
1602                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1603                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1604                         if((r_wateralpha.value < 1) && (t->currentmaterialflags & MATERIALFLAG_WATERALPHA))
1605                         {
1606                                 // this is the right thing to do for wateralpha
1607                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1608                                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1609                         }
1610                         else
1611                         {
1612                                 // this is the right thing to do for entity alpha
1613                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1614                                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1615                         }
1616                 }
1617                 else if (t->currentmaterialflags & MATERIALFLAG_REFRACTION)
1618                 {
1619                         mode = SHADERMODE_REFRACTION;
1620                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1621                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1622                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1623                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1624                 }
1625                 else
1626                 {
1627                         mode = SHADERMODE_GENERIC;
1628                         permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL;
1629                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1630                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1631                 }
1632                 if (vid.allowalphatocoverage)
1633                         GL_AlphaToCoverage(false);
1634         }
1635         else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
1636         {
1637                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1638                 {
1639                         switch(t->offsetmapping)
1640                         {
1641                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1642                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1643                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1644                         case OFFSETMAPPING_OFF: break;
1645                         }
1646                 }
1647                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1648                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1649                 // normalmap (deferred prepass), may use alpha test on diffuse
1650                 mode = SHADERMODE_DEFERREDGEOMETRY;
1651                 GL_BlendFunc(GL_ONE, GL_ZERO);
1652                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1653                 if (vid.allowalphatocoverage)
1654                         GL_AlphaToCoverage(false);
1655         }
1656         else if (rsurfacepass == RSURFPASS_RTLIGHT)
1657         {
1658                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1659                 {
1660                         switch(t->offsetmapping)
1661                         {
1662                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1663                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1664                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1665                         case OFFSETMAPPING_OFF: break;
1666                         }
1667                 }
1668                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1669                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1670                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1671                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1672                 // light source
1673                 mode = SHADERMODE_LIGHTSOURCE;
1674                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1675                         permutation |= SHADERPERMUTATION_CUBEFILTER;
1676                 if (VectorLength2(rtlightdiffuse) > 0)
1677                         permutation |= SHADERPERMUTATION_DIFFUSE;
1678                 if (VectorLength2(rtlightspecular) > 0)
1679                         permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1680                 if (r_refdef.fogenabled)
1681                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1682                 if (t->colormapping)
1683                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1684                 if (r_shadow_usingshadowmap2d)
1685                 {
1686                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1687                         if(r_shadow_shadowmapvsdct)
1688                                 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
1689
1690                         if (r_shadow_shadowmap2ddepthbuffer)
1691                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1692                 }
1693                 if (t->reflectmasktexture)
1694                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1695                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1696                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE);
1697                 if (vid.allowalphatocoverage)
1698                         GL_AlphaToCoverage(false);
1699         }
1700         else if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
1701         {
1702                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1703                 {
1704                         switch(t->offsetmapping)
1705                         {
1706                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1707                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1708                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1709                         case OFFSETMAPPING_OFF: break;
1710                         }
1711                 }
1712                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1713                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1714                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1715                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1716                 // directional model lighting
1717                 mode = SHADERMODE_LIGHTDIRECTION;
1718                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1719                         permutation |= SHADERPERMUTATION_GLOW;
1720                 if (VectorLength2(t->render_modellight_diffuse))
1721                         permutation |= SHADERPERMUTATION_DIFFUSE;
1722                 if (VectorLength2(t->render_modellight_specular) > 0)
1723                         permutation |= SHADERPERMUTATION_SPECULAR;
1724                 if (r_refdef.fogenabled)
1725                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1726                 if (t->colormapping)
1727                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1728                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1729                 {
1730                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1731                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1732
1733                         if (r_shadow_shadowmap2ddepthbuffer)
1734                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1735                 }
1736                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1737                         permutation |= SHADERPERMUTATION_REFLECTION;
1738                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1739                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1740                 if (t->reflectmasktexture)
1741                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1742                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld)
1743                 {
1744                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1745                         if (r_shadow_bouncegrid_state.directional)
1746                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1747                 }
1748                 GL_BlendFunc(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1749                 blendfuncflags = R_BlendFuncFlags(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1750                 // when using alphatocoverage, we don't need alphakill
1751                 if (vid.allowalphatocoverage)
1752                 {
1753                         if (r_transparent_alphatocoverage.integer)
1754                         {
1755                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1756                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1757                         }
1758                         else
1759                                 GL_AlphaToCoverage(false);
1760                 }
1761         }
1762         else
1763         {
1764                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1765                 {
1766                         switch(t->offsetmapping)
1767                         {
1768                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1769                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1770                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1771                         case OFFSETMAPPING_OFF: break;
1772                         }
1773                 }
1774                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1775                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1776                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1777                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1778                 // lightmapped wall
1779                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1780                         permutation |= SHADERPERMUTATION_GLOW;
1781                 if (r_refdef.fogenabled)
1782                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1783                 if (t->colormapping)
1784                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1785                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1786                 {
1787                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1788                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1789
1790                         if (r_shadow_shadowmap2ddepthbuffer)
1791                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1792                 }
1793                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1794                         permutation |= SHADERPERMUTATION_REFLECTION;
1795                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1796                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1797                 if (t->reflectmasktexture)
1798                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1799                 if (FAKELIGHT_ENABLED)
1800                 {
1801                         // fake lightmapping (q1bsp, q3bsp, fullbright map)
1802                         mode = SHADERMODE_FAKELIGHT;
1803                         permutation |= SHADERPERMUTATION_DIFFUSE;
1804                         if (VectorLength2(t->render_lightmap_specular) > 0)
1805                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1806                 }
1807                 else if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
1808                 {
1809                         // deluxemapping (light direction texture)
1810                         if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace)
1811                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1812                         else
1813                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1814                         permutation |= SHADERPERMUTATION_DIFFUSE;
1815                         if (VectorLength2(t->render_lightmap_specular) > 0)
1816                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1817                 }
1818                 else if (r_glsl_deluxemapping.integer >= 2)
1819                 {
1820                         // fake deluxemapping (uniform light direction in tangentspace)
1821                         if (rsurface.uselightmaptexture)
1822                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP;
1823                         else
1824                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR;
1825                         permutation |= SHADERPERMUTATION_DIFFUSE;
1826                         if (VectorLength2(t->render_lightmap_specular) > 0)
1827                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1828                 }
1829                 else if (rsurface.uselightmaptexture)
1830                 {
1831                         // ordinary lightmapping (q1bsp, q3bsp)
1832                         mode = SHADERMODE_LIGHTMAP;
1833                 }
1834                 else
1835                 {
1836                         // ordinary vertex coloring (q3bsp)
1837                         mode = SHADERMODE_VERTEXCOLOR;
1838                 }
1839                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld)
1840                 {
1841                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1842                         if (r_shadow_bouncegrid_state.directional)
1843                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1844                 }
1845                 GL_BlendFunc(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1846                 blendfuncflags = R_BlendFuncFlags(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1847                 // when using alphatocoverage, we don't need alphakill
1848                 if (vid.allowalphatocoverage)
1849                 {
1850                         if (r_transparent_alphatocoverage.integer)
1851                         {
1852                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1853                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1854                         }
1855                         else
1856                                 GL_AlphaToCoverage(false);
1857                 }
1858         }
1859         if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG))
1860                 permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE);
1861         if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1862                 permutation |= SHADERPERMUTATION_FOGALPHAHACK;
1863         switch(vid.renderpath)
1864         {
1865         case RENDERPATH_GL20:
1866         case RENDERPATH_GLES2:
1867                 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);
1868                 R_Mesh_VertexPointer(     3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
1869                 R_Mesh_ColorPointer(      4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
1870                 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
1871                 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
1872                 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
1873                 R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
1874                 R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
1875                 R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
1876                 R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
1877                 R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
1878                 // this has to be after RSurf_PrepareVerticesForBatch
1879                 if (rsurface.batchskeletaltransform3x4buffer)
1880                         permutation |= SHADERPERMUTATION_SKELETAL;
1881                 R_SetupShader_SetPermutationGLSL(mode, permutation);
1882 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1883                 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);
1884 #endif
1885                 if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
1886                 if (mode == SHADERMODE_LIGHTSOURCE)
1887                 {
1888                         if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
1889                         if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1890                         if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1891                         if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
1892                         if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
1893                         if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
1894         
1895                         // additive passes are only darkened by fog, not tinted
1896                         if (r_glsl_permutation->loc_FogColor >= 0)
1897                                 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1898                         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);
1899                 }
1900                 else
1901                 {
1902                         if (mode == SHADERMODE_FLATCOLOR)
1903                         {
1904                                 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]);
1905                         }
1906                         else if (mode == SHADERMODE_LIGHTDIRECTION)
1907                         {
1908                                 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]);
1909                                 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]);
1910                                 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]);
1911                                 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]);
1912                                 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]);
1913                                 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1914                                 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]);
1915                         }
1916                         else
1917                         {
1918                                 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]);
1919                                 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]);
1920                                 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]);
1921                                 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]);
1922                                 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]);
1923                         }
1924                         // additive passes are only darkened by fog, not tinted
1925                         if (r_glsl_permutation->loc_FogColor >= 0)
1926                         {
1927                                 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
1928                                         qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1929                                 else
1930                                         qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1931                         }
1932                         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);
1933                         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]);
1934                         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]);
1935                         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);
1936                         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);
1937                         if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, t->reflectmax - t->reflectmin);
1938                         if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, t->reflectmin);
1939                         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);
1940                         if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
1941                 }
1942                 if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
1943                 if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
1944                 if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
1945                 if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
1946                 {
1947                         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]);
1948                         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]);
1949                 }
1950                 else
1951                 {
1952                         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]);
1953                         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]);
1954                 }
1955
1956                 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]);
1957                 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));
1958                 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
1959                 if (r_glsl_permutation->loc_Color_Pants >= 0)
1960                 {
1961                         if (t->pantstexture)
1962                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
1963                         else
1964                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
1965                 }
1966                 if (r_glsl_permutation->loc_Color_Shirt >= 0)
1967                 {
1968                         if (t->shirttexture)
1969                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
1970                         else
1971                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
1972                 }
1973                 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]);
1974                 if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
1975                 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
1976                 if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
1977                 if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps,
1978                                 r_glsl_offsetmapping_scale.value*t->offsetscale,
1979                                 max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
1980                                 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
1981                                 max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
1982                         );
1983                 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);
1984                 if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, t->offsetbias);
1985                 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]);
1986                 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
1987                 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);}
1988                 if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
1989
1990                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First            , r_texture_white                                     );
1991                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second           , r_texture_white                                     );
1992                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps       , r_texture_gammaramps                                );
1993                 if (r_glsl_permutation->tex_Texture_Normal          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal           , t->nmaptexture                       );
1994                 if (r_glsl_permutation->tex_Texture_Color           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color            , t->basetexture                       );
1995                 if (r_glsl_permutation->tex_Texture_Gloss           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss            , t->glosstexture                      );
1996                 if (r_glsl_permutation->tex_Texture_Glow            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow             , t->glowtexture                       );
1997                 if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal  , t->backgroundnmaptexture             );
1998                 if (r_glsl_permutation->tex_Texture_SecondaryColor  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor   , t->backgroundbasetexture             );
1999                 if (r_glsl_permutation->tex_Texture_SecondaryGloss  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss   , t->backgroundglosstexture            );
2000                 if (r_glsl_permutation->tex_Texture_SecondaryGlow   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow    , t->backgroundglowtexture             );
2001                 if (r_glsl_permutation->tex_Texture_Pants           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants            , t->pantstexture                      );
2002                 if (r_glsl_permutation->tex_Texture_Shirt           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt            , t->shirttexture                      );
2003                 if (r_glsl_permutation->tex_Texture_ReflectMask     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask      , t->reflectmasktexture                );
2004                 if (r_glsl_permutation->tex_Texture_ReflectCube     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube      , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
2005                 if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture                          );
2006                 if (r_glsl_permutation->tex_Texture_FogMask         >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask          , r_texture_fogattenuation                            );
2007                 if (r_glsl_permutation->tex_Texture_Lightmap        >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap         , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
2008                 if (r_glsl_permutation->tex_Texture_Deluxemap       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Deluxemap        , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap);
2009                 if (r_glsl_permutation->tex_Texture_Attenuation     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation      , r_shadow_attenuationgradienttexture                 );
2010                 if (rsurfacepass == RSURFPASS_BACKGROUND)
2011                 {
2012                         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);
2013                         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);
2014                         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);
2015                 }
2016                 else
2017                 {
2018                         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);
2019                 }
2020                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap   , r_shadow_prepassgeometrynormalmaptexture            );
2021                 if (r_glsl_permutation->tex_Texture_ScreenDiffuse   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse     , r_shadow_prepasslightingdiffusetexture              );
2022                 if (r_glsl_permutation->tex_Texture_ScreenSpecular  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular    , r_shadow_prepasslightingspeculartexture             );
2023                 if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
2024                 {
2025                         if (r_glsl_permutation->tex_Texture_ShadowMap2D     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture                           );
2026                         if (rsurface.rtlight)
2027                         {
2028                                 if (r_glsl_permutation->tex_Texture_Cube            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube              , rsurface.rtlight->currentcubemap                    );
2029                                 if (r_glsl_permutation->tex_Texture_CubeProjection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection    , r_shadow_shadowmapvsdcttexture                      );
2030                         }
2031                 }
2032                 if (r_glsl_permutation->tex_Texture_BounceGrid  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
2033                 CHECKGLERROR
2034                 break;
2035         }
2036 }
2037
2038 void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
2039 {
2040         // select a permutation of the lighting shader appropriate to this
2041         // combination of texture, entity, light source, and fogging, only use the
2042         // minimum features necessary to avoid wasting rendering time in the
2043         // fragment shader on features that are not being used
2044         dpuint64 permutation = 0;
2045         unsigned int mode = 0;
2046         const float *lightcolorbase = rtlight->currentcolor;
2047         float ambientscale = rtlight->ambientscale;
2048         float diffusescale = rtlight->diffusescale;
2049         float specularscale = rtlight->specularscale;
2050         // this is the location of the light in view space
2051         vec3_t viewlightorigin;
2052         // this transforms from view space (camera) to light space (cubemap)
2053         matrix4x4_t viewtolight;
2054         matrix4x4_t lighttoview;
2055         float viewtolight16f[16];
2056         // light source
2057         mode = SHADERMODE_DEFERREDLIGHTSOURCE;
2058         if (rtlight->currentcubemap != r_texture_whitecube)
2059                 permutation |= SHADERPERMUTATION_CUBEFILTER;
2060         if (diffusescale > 0)
2061                 permutation |= SHADERPERMUTATION_DIFFUSE;
2062         if (specularscale > 0 && r_shadow_gloss.integer > 0)
2063                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2064         if (r_shadow_usingshadowmap2d)
2065         {
2066                 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
2067                 if (r_shadow_shadowmapvsdct)
2068                         permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
2069
2070                 if (r_shadow_shadowmap2ddepthbuffer)
2071                         permutation |= SHADERPERMUTATION_DEPTHRGB;
2072         }
2073         if (vid.allowalphatocoverage)
2074                 GL_AlphaToCoverage(false);
2075         Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
2076         Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
2077         Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
2078         Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
2079         switch(vid.renderpath)
2080         {
2081         case RENDERPATH_GL20:
2082         case RENDERPATH_GLES2:
2083                 R_SetupShader_SetPermutationGLSL(mode, permutation);
2084                 if (r_glsl_permutation->loc_LightPosition             >= 0) qglUniform3f(       r_glsl_permutation->loc_LightPosition            , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
2085                 if (r_glsl_permutation->loc_ViewToLight               >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight              , 1, false, viewtolight16f);
2086                 if (r_glsl_permutation->loc_DeferredColor_Ambient     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Ambient    , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
2087                 if (r_glsl_permutation->loc_DeferredColor_Diffuse     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
2088                 if (r_glsl_permutation->loc_DeferredColor_Specular    >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Specular   , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
2089                 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]);
2090                 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]);
2091                 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);
2092                 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]);
2093                 if (r_glsl_permutation->loc_PixelToScreenTexCoord     >= 0) qglUniform2f(       r_glsl_permutation->loc_PixelToScreenTexCoord    , 1.0f/vid.width, 1.0f/vid.height);
2094
2095                 if (r_glsl_permutation->tex_Texture_Attenuation       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation        , r_shadow_attenuationgradienttexture                 );
2096                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap    , r_shadow_prepassgeometrynormalmaptexture            );
2097                 if (r_glsl_permutation->tex_Texture_Cube              >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube               , rsurface.rtlight->currentcubemap                    );
2098                 if (r_glsl_permutation->tex_Texture_ShadowMap2D       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D        , r_shadow_shadowmap2ddepthtexture                    );
2099                 if (r_glsl_permutation->tex_Texture_CubeProjection    >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection     , r_shadow_shadowmapvsdcttexture                      );
2100                 break;
2101         }
2102 }
2103
2104 #define SKINFRAME_HASH 1024
2105
2106 typedef struct
2107 {
2108         unsigned int loadsequence; // incremented each level change
2109         memexpandablearray_t array;
2110         skinframe_t *hash[SKINFRAME_HASH];
2111 }
2112 r_skinframe_t;
2113 r_skinframe_t r_skinframe;
2114
2115 void R_SkinFrame_PrepareForPurge(void)
2116 {
2117         r_skinframe.loadsequence++;
2118         // wrap it without hitting zero
2119         if (r_skinframe.loadsequence >= 200)
2120                 r_skinframe.loadsequence = 1;
2121 }
2122
2123 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
2124 {
2125         if (!skinframe)
2126                 return;
2127         // mark the skinframe as used for the purging code
2128         skinframe->loadsequence = r_skinframe.loadsequence;
2129 }
2130
2131 void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
2132 {
2133         if (s == NULL)
2134                 return;
2135         if (s->merged == s->base)
2136                 s->merged = NULL;
2137         R_PurgeTexture(s->stain); s->stain = NULL;
2138         R_PurgeTexture(s->merged); s->merged = NULL;
2139         R_PurgeTexture(s->base); s->base = NULL;
2140         R_PurgeTexture(s->pants); s->pants = NULL;
2141         R_PurgeTexture(s->shirt); s->shirt = NULL;
2142         R_PurgeTexture(s->nmap); s->nmap = NULL;
2143         R_PurgeTexture(s->gloss); s->gloss = NULL;
2144         R_PurgeTexture(s->glow); s->glow = NULL;
2145         R_PurgeTexture(s->fog); s->fog = NULL;
2146         R_PurgeTexture(s->reflect); s->reflect = NULL;
2147         s->loadsequence = 0;
2148 }
2149
2150 void R_SkinFrame_Purge(void)
2151 {
2152         int i;
2153         skinframe_t *s;
2154         for (i = 0;i < SKINFRAME_HASH;i++)
2155         {
2156                 for (s = r_skinframe.hash[i];s;s = s->next)
2157                 {
2158                         if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
2159                                 R_SkinFrame_PurgeSkinFrame(s);
2160                 }
2161         }
2162 }
2163
2164 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
2165         skinframe_t *item;
2166         char basename[MAX_QPATH];
2167
2168         Image_StripImageExtension(name, basename, sizeof(basename));
2169
2170         if( last == NULL ) {
2171                 int hashindex;
2172                 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2173                 item = r_skinframe.hash[hashindex];
2174         } else {
2175                 item = last->next;
2176         }
2177
2178         // linearly search through the hash bucket
2179         for( ; item ; item = item->next ) {
2180                 if( !strcmp( item->basename, basename ) ) {
2181                         return item;
2182                 }
2183         }
2184         return NULL;
2185 }
2186
2187 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add)
2188 {
2189         skinframe_t *item;
2190         int hashindex;
2191         char basename[MAX_QPATH];
2192
2193         Image_StripImageExtension(name, basename, sizeof(basename));
2194
2195         hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2196         for (item = r_skinframe.hash[hashindex];item;item = item->next)
2197                 if (!strcmp(item->basename, basename) && (comparecrc < 0 || (item->textureflags == textureflags && item->comparewidth == comparewidth && item->compareheight == compareheight && item->comparecrc == comparecrc)))
2198                         break;
2199
2200         if (!item)
2201         {
2202                 if (!add)
2203                         return NULL;
2204                 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
2205                 memset(item, 0, sizeof(*item));
2206                 strlcpy(item->basename, basename, sizeof(item->basename));
2207                 item->textureflags = textureflags & ~TEXF_FORCE_RELOAD;
2208                 item->comparewidth = comparewidth;
2209                 item->compareheight = compareheight;
2210                 item->comparecrc = comparecrc;
2211                 item->next = r_skinframe.hash[hashindex];
2212                 r_skinframe.hash[hashindex] = item;
2213         }
2214         else if (textureflags & TEXF_FORCE_RELOAD)
2215         {
2216                 if (!add)
2217                         return NULL;
2218                 R_SkinFrame_PurgeSkinFrame(item);
2219         }
2220
2221         R_SkinFrame_MarkUsed(item);
2222         return item;
2223 }
2224
2225 #define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
2226         { \
2227                 unsigned long long avgcolor[5], wsum; \
2228                 int pix, comp, w; \
2229                 avgcolor[0] = 0; \
2230                 avgcolor[1] = 0; \
2231                 avgcolor[2] = 0; \
2232                 avgcolor[3] = 0; \
2233                 avgcolor[4] = 0; \
2234                 wsum = 0; \
2235                 for(pix = 0; pix < cnt; ++pix) \
2236                 { \
2237                         w = 0; \
2238                         for(comp = 0; comp < 3; ++comp) \
2239                                 w += getpixel; \
2240                         if(w) /* ignore perfectly black pixels because that is better for model skins */ \
2241                         { \
2242                                 ++wsum; \
2243                                 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2244                                 w = getpixel; \
2245                                 for(comp = 0; comp < 3; ++comp) \
2246                                         avgcolor[comp] += getpixel * w; \
2247                                 avgcolor[3] += w; \
2248                         } \
2249                         /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2250                         avgcolor[4] += getpixel; \
2251                 } \
2252                 if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
2253                         avgcolor[3] = 1; \
2254                 skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
2255                 skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
2256                 skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
2257                 skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
2258         }
2259
2260 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2261 {
2262         skinframe_t *skinframe;
2263
2264         if (cls.state == ca_dedicated)
2265                 return NULL;
2266
2267         // return an existing skinframe if already loaded
2268         // if loading of the first image fails, don't make a new skinframe as it
2269         // would cause all future lookups of this to be missing
2270         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, -1, false);
2271         if (skinframe && skinframe->base)
2272                 return skinframe;
2273
2274         return R_SkinFrame_LoadExternal_SkinFrame(skinframe, name, textureflags, complain, fallbacknotexture);
2275 }
2276
2277 extern cvar_t gl_picmip;
2278 skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2279 {
2280         int j;
2281         unsigned char *pixels;
2282         unsigned char *bumppixels;
2283         unsigned char *basepixels = NULL;
2284         int basepixels_width = 0;
2285         int basepixels_height = 0;
2286         rtexture_t *ddsbase = NULL;
2287         qboolean ddshasalpha = false;
2288         float ddsavgcolor[4];
2289         char basename[MAX_QPATH];
2290         int miplevel = R_PicmipForFlags(textureflags);
2291         int savemiplevel = miplevel;
2292         int mymiplevel;
2293         char vabuf[1024];
2294
2295         if (cls.state == ca_dedicated)
2296                 return NULL;
2297
2298         Image_StripImageExtension(name, basename, sizeof(basename));
2299
2300         // check for DDS texture file first
2301         if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2302         {
2303                 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2304                 if (basepixels == NULL && fallbacknotexture)
2305                         basepixels = Image_GenerateNoTexture();
2306                 if (basepixels == NULL)
2307                         return NULL;
2308         }
2309
2310         // FIXME handle miplevel
2311
2312         if (developer_loading.integer)
2313                 Con_Printf("loading skin \"%s\"\n", name);
2314
2315         // we've got some pixels to store, so really allocate this new texture now
2316         if (!skinframe)
2317                 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2318         textureflags &= ~TEXF_FORCE_RELOAD;
2319         skinframe->stain = NULL;
2320         skinframe->merged = NULL;
2321         skinframe->base = NULL;
2322         skinframe->pants = NULL;
2323         skinframe->shirt = NULL;
2324         skinframe->nmap = NULL;
2325         skinframe->gloss = NULL;
2326         skinframe->glow = NULL;
2327         skinframe->fog = NULL;
2328         skinframe->reflect = NULL;
2329         skinframe->hasalpha = false;
2330         // we could store the q2animname here too
2331
2332         if (ddsbase)
2333         {
2334                 skinframe->base = ddsbase;
2335                 skinframe->hasalpha = ddshasalpha;
2336                 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2337                 if (r_loadfog && skinframe->hasalpha)
2338                         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);
2339                 //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]);
2340         }
2341         else
2342         {
2343                 basepixels_width = image_width;
2344                 basepixels_height = image_height;
2345                 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);
2346                 if (textureflags & TEXF_ALPHA)
2347                 {
2348                         for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2349                         {
2350                                 if (basepixels[j] < 255)
2351                                 {
2352                                         skinframe->hasalpha = true;
2353                                         break;
2354                                 }
2355                         }
2356                         if (r_loadfog && skinframe->hasalpha)
2357                         {
2358                                 // has transparent pixels
2359                                 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2360                                 for (j = 0;j < image_width * image_height * 4;j += 4)
2361                                 {
2362                                         pixels[j+0] = 255;
2363                                         pixels[j+1] = 255;
2364                                         pixels[j+2] = 255;
2365                                         pixels[j+3] = basepixels[j+3];
2366                                 }
2367                                 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);
2368                                 Mem_Free(pixels);
2369                         }
2370                 }
2371                 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2372 #ifndef USE_GLES2
2373                 //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]);
2374                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->base)
2375                         R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2376                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->fog)
2377                         R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2378 #endif
2379         }
2380
2381         if (r_loaddds)
2382         {
2383                 mymiplevel = savemiplevel;
2384                 if (r_loadnormalmap)
2385                         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);
2386                 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2387                 if (r_loadgloss)
2388                         skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2389                 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2390                 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2391                 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2392         }
2393
2394         // _norm is the name used by tenebrae and has been adopted as standard
2395         if (r_loadnormalmap && skinframe->nmap == NULL)
2396         {
2397                 mymiplevel = savemiplevel;
2398                 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2399                 {
2400                         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);
2401                         Mem_Free(pixels);
2402                         pixels = NULL;
2403                 }
2404                 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2405                 {
2406                         pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2407                         Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2408                         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);
2409                         Mem_Free(pixels);
2410                         Mem_Free(bumppixels);
2411                 }
2412                 else if (r_shadow_bumpscale_basetexture.value > 0)
2413                 {
2414                         pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2415                         Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2416                         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);
2417                         Mem_Free(pixels);
2418                 }
2419 #ifndef USE_GLES2
2420                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->nmap)
2421                         R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2422 #endif
2423         }
2424
2425         // _luma is supported only for tenebrae compatibility
2426         // _glow is the preferred name
2427         mymiplevel = savemiplevel;
2428         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))))
2429         {
2430                 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);
2431 #ifndef USE_GLES2
2432                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->glow)
2433                         R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2434 #endif
2435                 Mem_Free(pixels);pixels = NULL;
2436         }
2437
2438         mymiplevel = savemiplevel;
2439         if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2440         {
2441                 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);
2442 #ifndef USE_GLES2
2443                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->gloss)
2444                         R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2445 #endif
2446                 Mem_Free(pixels);
2447                 pixels = NULL;
2448         }
2449
2450         mymiplevel = savemiplevel;
2451         if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2452         {
2453                 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);
2454 #ifndef USE_GLES2
2455                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->pants)
2456                         R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2457 #endif
2458                 Mem_Free(pixels);
2459                 pixels = NULL;
2460         }
2461
2462         mymiplevel = savemiplevel;
2463         if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2464         {
2465                 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);
2466 #ifndef USE_GLES2
2467                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->shirt)
2468                         R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2469 #endif
2470                 Mem_Free(pixels);
2471                 pixels = NULL;
2472         }
2473
2474         mymiplevel = savemiplevel;
2475         if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2476         {
2477                 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);
2478 #ifndef USE_GLES2
2479                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->reflect)
2480                         R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2481 #endif
2482                 Mem_Free(pixels);
2483                 pixels = NULL;
2484         }
2485
2486         if (basepixels)
2487                 Mem_Free(basepixels);
2488
2489         return skinframe;
2490 }
2491
2492 // this is only used by .spr32 sprites, HL .spr files, HL .bsp files
2493 skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, qboolean sRGB)
2494 {
2495         int i;
2496         skinframe_t *skinframe;
2497         char vabuf[1024];
2498
2499         if (cls.state == ca_dedicated)
2500                 return NULL;
2501
2502         // if already loaded just return it, otherwise make a new skinframe
2503         skinframe = R_SkinFrame_Find(name, textureflags, width, height, (!(textureflags & TEXF_FORCE_RELOAD) && skindata) ? CRC_Block(skindata, width*height*4) : -1, true);
2504         if (skinframe->base)
2505                 return skinframe;
2506         textureflags &= ~TEXF_FORCE_RELOAD;
2507
2508         skinframe->stain = NULL;
2509         skinframe->merged = NULL;
2510         skinframe->base = NULL;
2511         skinframe->pants = NULL;
2512         skinframe->shirt = NULL;
2513         skinframe->nmap = NULL;
2514         skinframe->gloss = NULL;
2515         skinframe->glow = NULL;
2516         skinframe->fog = NULL;
2517         skinframe->reflect = NULL;
2518         skinframe->hasalpha = false;
2519
2520         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2521         if (!skindata)
2522                 return NULL;
2523
2524         if (developer_loading.integer)
2525                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2526
2527         if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2528         {
2529                 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2530                 unsigned char *b = a + width * height * 4;
2531                 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2532                 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);
2533                 Mem_Free(a);
2534         }
2535         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2536         if (textureflags & TEXF_ALPHA)
2537         {
2538                 for (i = 3;i < width * height * 4;i += 4)
2539                 {
2540                         if (skindata[i] < 255)
2541                         {
2542                                 skinframe->hasalpha = true;
2543                                 break;
2544                         }
2545                 }
2546                 if (r_loadfog && skinframe->hasalpha)
2547                 {
2548                         unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2549                         memcpy(fogpixels, skindata, width * height * 4);
2550                         for (i = 0;i < width * height * 4;i += 4)
2551                                 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2552                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2553                         Mem_Free(fogpixels);
2554                 }
2555         }
2556
2557         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2558         //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]);
2559
2560         return skinframe;
2561 }
2562
2563 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2564 {
2565         int i;
2566         int featuresmask;
2567         skinframe_t *skinframe;
2568
2569         if (cls.state == ca_dedicated)
2570                 return NULL;
2571
2572         // if already loaded just return it, otherwise make a new skinframe
2573         skinframe = R_SkinFrame_Find(name, textureflags, width, height, (!(textureflags & TEXF_FORCE_RELOAD) && skindata) ? CRC_Block(skindata, width*height) : -1, true);
2574         if (skinframe->base)
2575                 return skinframe;
2576         //textureflags &= ~TEXF_FORCE_RELOAD;
2577
2578         skinframe->stain = NULL;
2579         skinframe->merged = NULL;
2580         skinframe->base = NULL;
2581         skinframe->pants = NULL;
2582         skinframe->shirt = NULL;
2583         skinframe->nmap = NULL;
2584         skinframe->gloss = NULL;
2585         skinframe->glow = NULL;
2586         skinframe->fog = NULL;
2587         skinframe->reflect = NULL;
2588         skinframe->hasalpha = false;
2589
2590         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2591         if (!skindata)
2592                 return NULL;
2593
2594         if (developer_loading.integer)
2595                 Con_Printf("loading quake skin \"%s\"\n", name);
2596
2597         // 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)
2598         skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2599         memcpy(skinframe->qpixels, skindata, width*height);
2600         skinframe->qwidth = width;
2601         skinframe->qheight = height;
2602
2603         featuresmask = 0;
2604         for (i = 0;i < width * height;i++)
2605                 featuresmask |= palette_featureflags[skindata[i]];
2606
2607         skinframe->hasalpha = false;
2608         // fence textures
2609         if (name[0] == '{')
2610                 skinframe->hasalpha = true;
2611         skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2612         skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2613         skinframe->qgeneratemerged = true;
2614         skinframe->qgeneratebase = skinframe->qhascolormapping;
2615         skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2616
2617         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2618         //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]);
2619
2620         return skinframe;
2621 }
2622
2623 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboolean colormapped)
2624 {
2625         int width;
2626         int height;
2627         unsigned char *skindata;
2628         char vabuf[1024];
2629
2630         if (!skinframe->qpixels)
2631                 return;
2632
2633         if (!skinframe->qhascolormapping)
2634                 colormapped = false;
2635
2636         if (colormapped)
2637         {
2638                 if (!skinframe->qgeneratebase)
2639                         return;
2640         }
2641         else
2642         {
2643                 if (!skinframe->qgeneratemerged)
2644                         return;
2645         }
2646
2647         width = skinframe->qwidth;
2648         height = skinframe->qheight;
2649         skindata = skinframe->qpixels;
2650
2651         if (skinframe->qgeneratenmap)
2652         {
2653                 unsigned char *a, *b;
2654                 skinframe->qgeneratenmap = false;
2655                 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2656                 b = a + width * height * 4;
2657                 // use either a custom palette or the quake palette
2658                 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2659                 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2660                 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);
2661                 Mem_Free(a);
2662         }
2663
2664         if (skinframe->qgenerateglow)
2665         {
2666                 skinframe->qgenerateglow = false;
2667                 if (skinframe->hasalpha) // fence textures
2668                         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
2669                 else
2670                         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
2671         }
2672
2673         if (colormapped)
2674         {
2675                 skinframe->qgeneratebase = false;
2676                 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);
2677                 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);
2678                 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);
2679         }
2680         else
2681         {
2682                 skinframe->qgeneratemerged = false;
2683                 if (skinframe->hasalpha) // fence textures
2684                         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);
2685                 else
2686                         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);
2687         }
2688
2689         if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2690         {
2691                 Mem_Free(skinframe->qpixels);
2692                 skinframe->qpixels = NULL;
2693         }
2694 }
2695
2696 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)
2697 {
2698         int i;
2699         skinframe_t *skinframe;
2700         char vabuf[1024];
2701
2702         if (cls.state == ca_dedicated)
2703                 return NULL;
2704
2705         // if already loaded just return it, otherwise make a new skinframe
2706         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2707         if (skinframe->base)
2708                 return skinframe;
2709         textureflags &= ~TEXF_FORCE_RELOAD;
2710
2711         skinframe->stain = NULL;
2712         skinframe->merged = NULL;
2713         skinframe->base = NULL;
2714         skinframe->pants = NULL;
2715         skinframe->shirt = NULL;
2716         skinframe->nmap = NULL;
2717         skinframe->gloss = NULL;
2718         skinframe->glow = NULL;
2719         skinframe->fog = NULL;
2720         skinframe->reflect = NULL;
2721         skinframe->hasalpha = false;
2722
2723         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2724         if (!skindata)
2725                 return NULL;
2726
2727         if (developer_loading.integer)
2728                 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2729
2730         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2731         if ((textureflags & TEXF_ALPHA) && alphapalette)
2732         {
2733                 for (i = 0;i < width * height;i++)
2734                 {
2735                         if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2736                         {
2737                                 skinframe->hasalpha = true;
2738                                 break;
2739                         }
2740                 }
2741                 if (r_loadfog && skinframe->hasalpha)
2742                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2743         }
2744
2745         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2746         //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]);
2747
2748         return skinframe;
2749 }
2750
2751 skinframe_t *R_SkinFrame_LoadMissing(void)
2752 {
2753         skinframe_t *skinframe;
2754
2755         if (cls.state == ca_dedicated)
2756                 return NULL;
2757
2758         skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2759         skinframe->stain = NULL;
2760         skinframe->merged = NULL;
2761         skinframe->base = NULL;
2762         skinframe->pants = NULL;
2763         skinframe->shirt = NULL;
2764         skinframe->nmap = NULL;
2765         skinframe->gloss = NULL;
2766         skinframe->glow = NULL;
2767         skinframe->fog = NULL;
2768         skinframe->reflect = NULL;
2769         skinframe->hasalpha = false;
2770
2771         skinframe->avgcolor[0] = rand() / RAND_MAX;
2772         skinframe->avgcolor[1] = rand() / RAND_MAX;
2773         skinframe->avgcolor[2] = rand() / RAND_MAX;
2774         skinframe->avgcolor[3] = 1;
2775
2776         return skinframe;
2777 }
2778
2779 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2780 {
2781         int x, y;
2782         static unsigned char pix[16][16][4];
2783
2784         if (cls.state == ca_dedicated)
2785                 return NULL;
2786
2787         // this makes a light grey/dark grey checkerboard texture
2788         if (!pix[0][0][3])
2789         {
2790                 for (y = 0; y < 16; y++)
2791                 {
2792                         for (x = 0; x < 16; x++)
2793                         {
2794                                 if ((y < 8) ^ (x < 8))
2795                                 {
2796                                         pix[y][x][0] = 128;
2797                                         pix[y][x][1] = 128;
2798                                         pix[y][x][2] = 128;
2799                                         pix[y][x][3] = 255;
2800                                 }
2801                                 else
2802                                 {
2803                                         pix[y][x][0] = 64;
2804                                         pix[y][x][1] = 64;
2805                                         pix[y][x][2] = 64;
2806                                         pix[y][x][3] = 255;
2807                                 }
2808                         }
2809                 }
2810         }
2811
2812         return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, pix[0][0], 16, 16, false);
2813 }
2814
2815 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qboolean sRGB)
2816 {
2817         skinframe_t *skinframe;
2818         if (cls.state == ca_dedicated)
2819                 return NULL;
2820         // if already loaded just return it, otherwise make a new skinframe
2821         skinframe = R_SkinFrame_Find(name, textureflags, width, height, (textureflags & TEXF_FORCE_RELOAD) ? -1 : 0, true);
2822         if (skinframe->base)
2823                 return skinframe;
2824         textureflags &= ~TEXF_FORCE_RELOAD;
2825         skinframe->stain = NULL;
2826         skinframe->merged = NULL;
2827         skinframe->base = NULL;
2828         skinframe->pants = NULL;
2829         skinframe->shirt = NULL;
2830         skinframe->nmap = NULL;
2831         skinframe->gloss = NULL;
2832         skinframe->glow = NULL;
2833         skinframe->fog = NULL;
2834         skinframe->reflect = NULL;
2835         skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2836         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2837         if (!tex)
2838                 return NULL;
2839         if (developer_loading.integer)
2840                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2841         skinframe->base = skinframe->merged = tex;
2842         Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2843         return skinframe;
2844 }
2845
2846 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2847 typedef struct suffixinfo_s
2848 {
2849         const char *suffix;
2850         qboolean flipx, flipy, flipdiagonal;
2851 }
2852 suffixinfo_t;
2853 static suffixinfo_t suffix[3][6] =
2854 {
2855         {
2856                 {"px",   false, false, false},
2857                 {"nx",   false, false, false},
2858                 {"py",   false, false, false},
2859                 {"ny",   false, false, false},
2860                 {"pz",   false, false, false},
2861                 {"nz",   false, false, false}
2862         },
2863         {
2864                 {"posx", false, false, false},
2865                 {"negx", false, false, false},
2866                 {"posy", false, false, false},
2867                 {"negy", false, false, false},
2868                 {"posz", false, false, false},
2869                 {"negz", false, false, false}
2870         },
2871         {
2872                 {"rt",    true, false,  true},
2873                 {"lf",   false,  true,  true},
2874                 {"ft",    true,  true, false},
2875                 {"bk",   false, false, false},
2876                 {"up",    true, false,  true},
2877                 {"dn",    true, false,  true}
2878         }
2879 };
2880
2881 static int componentorder[4] = {0, 1, 2, 3};
2882
2883 static rtexture_t *R_LoadCubemap(const char *basename)
2884 {
2885         int i, j, cubemapsize;
2886         unsigned char *cubemappixels, *image_buffer;
2887         rtexture_t *cubemaptexture;
2888         char name[256];
2889         // must start 0 so the first loadimagepixels has no requested width/height
2890         cubemapsize = 0;
2891         cubemappixels = NULL;
2892         cubemaptexture = NULL;
2893         // keep trying different suffix groups (posx, px, rt) until one loads
2894         for (j = 0;j < 3 && !cubemappixels;j++)
2895         {
2896                 // load the 6 images in the suffix group
2897                 for (i = 0;i < 6;i++)
2898                 {
2899                         // generate an image name based on the base and and suffix
2900                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2901                         // load it
2902                         if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
2903                         {
2904                                 // an image loaded, make sure width and height are equal
2905                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
2906                                 {
2907                                         // if this is the first image to load successfully, allocate the cubemap memory
2908                                         if (!cubemappixels && image_width >= 1)
2909                                         {
2910                                                 cubemapsize = image_width;
2911                                                 // note this clears to black, so unavailable sides are black
2912                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2913                                         }
2914                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2915                                         if (cubemappixels)
2916                                                 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);
2917                                 }
2918                                 else
2919                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2920                                 // free the image
2921                                 Mem_Free(image_buffer);
2922                         }
2923                 }
2924         }
2925         // if a cubemap loaded, upload it
2926         if (cubemappixels)
2927         {
2928                 if (developer_loading.integer)
2929                         Con_Printf("loading cubemap \"%s\"\n", basename);
2930
2931                 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);
2932                 Mem_Free(cubemappixels);
2933         }
2934         else
2935         {
2936                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
2937                 if (developer_loading.integer)
2938                 {
2939                         Con_Printf("(tried tried images ");
2940                         for (j = 0;j < 3;j++)
2941                                 for (i = 0;i < 6;i++)
2942                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2943                         Con_Print(" and was unable to find any of them).\n");
2944                 }
2945         }
2946         return cubemaptexture;
2947 }
2948
2949 rtexture_t *R_GetCubemap(const char *basename)
2950 {
2951         int i;
2952         for (i = 0;i < r_texture_numcubemaps;i++)
2953                 if (r_texture_cubemaps[i] != NULL)
2954                         if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
2955                                 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
2956         if (i >= MAX_CUBEMAPS || !r_main_mempool)
2957                 return r_texture_whitecube;
2958         r_texture_numcubemaps++;
2959         r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
2960         strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
2961         r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
2962         return r_texture_cubemaps[i]->texture;
2963 }
2964
2965 static void R_Main_FreeViewCache(void)
2966 {
2967         if (r_refdef.viewcache.entityvisible)
2968                 Mem_Free(r_refdef.viewcache.entityvisible);
2969         if (r_refdef.viewcache.world_pvsbits)
2970                 Mem_Free(r_refdef.viewcache.world_pvsbits);
2971         if (r_refdef.viewcache.world_leafvisible)
2972                 Mem_Free(r_refdef.viewcache.world_leafvisible);
2973         if (r_refdef.viewcache.world_surfacevisible)
2974                 Mem_Free(r_refdef.viewcache.world_surfacevisible);
2975         memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
2976 }
2977
2978 static void R_Main_ResizeViewCache(void)
2979 {
2980         int numentities = r_refdef.scene.numentities;
2981         int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
2982         int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
2983         int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
2984         int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
2985         if (r_refdef.viewcache.maxentities < numentities)
2986         {
2987                 r_refdef.viewcache.maxentities = numentities;
2988                 if (r_refdef.viewcache.entityvisible)
2989                         Mem_Free(r_refdef.viewcache.entityvisible);
2990                 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
2991         }
2992         if (r_refdef.viewcache.world_numclusters != numclusters)
2993         {
2994                 r_refdef.viewcache.world_numclusters = numclusters;
2995                 r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
2996                 if (r_refdef.viewcache.world_pvsbits)
2997                         Mem_Free(r_refdef.viewcache.world_pvsbits);
2998                 r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
2999         }
3000         if (r_refdef.viewcache.world_numleafs != numleafs)
3001         {
3002                 r_refdef.viewcache.world_numleafs = numleafs;
3003                 if (r_refdef.viewcache.world_leafvisible)
3004                         Mem_Free(r_refdef.viewcache.world_leafvisible);
3005                 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
3006         }
3007         if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
3008         {
3009                 r_refdef.viewcache.world_numsurfaces = numsurfaces;
3010                 if (r_refdef.viewcache.world_surfacevisible)
3011                         Mem_Free(r_refdef.viewcache.world_surfacevisible);
3012                 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
3013         }
3014 }
3015
3016 extern rtexture_t *loadingscreentexture;
3017 static void gl_main_start(void)
3018 {
3019         loadingscreentexture = NULL;
3020         r_texture_blanknormalmap = NULL;
3021         r_texture_white = NULL;
3022         r_texture_grey128 = NULL;
3023         r_texture_black = NULL;
3024         r_texture_whitecube = NULL;
3025         r_texture_normalizationcube = NULL;
3026         r_texture_fogattenuation = NULL;
3027         r_texture_fogheighttexture = NULL;
3028         r_texture_gammaramps = NULL;
3029         r_texture_numcubemaps = 0;
3030         r_uniformbufferalignment = 32;
3031
3032         r_loaddds = r_texture_dds_load.integer != 0;
3033         r_savedds = vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3034
3035         switch(vid.renderpath)
3036         {
3037         case RENDERPATH_GL20:
3038         case RENDERPATH_GLES2:
3039                 Cvar_SetValueQuick(&r_textureunits, vid.texunits);
3040                 Cvar_SetValueQuick(&gl_combine, 1);
3041                 Cvar_SetValueQuick(&r_glsl, 1);
3042                 r_loadnormalmap = true;
3043                 r_loadgloss = true;
3044                 r_loadfog = false;
3045 #ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
3046                 if (vid.support.arb_uniform_buffer_object)
3047                         qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
3048 #endif
3049                         break;
3050         }
3051
3052         R_AnimCache_Free();
3053         R_FrameData_Reset();
3054         R_BufferData_Reset();
3055
3056         r_numqueries = 0;
3057         r_maxqueries = 0;
3058         memset(r_queries, 0, sizeof(r_queries));
3059
3060         r_qwskincache = NULL;
3061         r_qwskincache_size = 0;
3062
3063         // due to caching of texture_t references, the collision cache must be reset
3064         Collision_Cache_Reset(true);
3065
3066         // set up r_skinframe loading system for textures
3067         memset(&r_skinframe, 0, sizeof(r_skinframe));
3068         r_skinframe.loadsequence = 1;
3069         Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
3070
3071         r_main_texturepool = R_AllocTexturePool();
3072         R_BuildBlankTextures();
3073         R_BuildNoTexture();
3074         if (vid.support.arb_texture_cube_map)
3075         {
3076                 R_BuildWhiteCube();
3077                 R_BuildNormalizationCube();
3078         }
3079         r_texture_fogattenuation = NULL;
3080         r_texture_fogheighttexture = NULL;
3081         r_texture_gammaramps = NULL;
3082         //r_texture_fogintensity = NULL;
3083         memset(&r_fb, 0, sizeof(r_fb));
3084         Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
3085         r_glsl_permutation = NULL;
3086         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3087         Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
3088         memset(&r_svbsp, 0, sizeof (r_svbsp));
3089
3090         memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
3091         r_texture_numcubemaps = 0;
3092
3093         r_refdef.fogmasktable_density = 0;
3094
3095 #ifdef __ANDROID__
3096         // For Steelstorm Android
3097         // FIXME CACHE the program and reload
3098         // FIXME see possible combinations for SS:BR android
3099         Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
3100         R_SetupShader_SetPermutationGLSL(0, 12);
3101         R_SetupShader_SetPermutationGLSL(0, 13);
3102         R_SetupShader_SetPermutationGLSL(0, 8388621);
3103         R_SetupShader_SetPermutationGLSL(3, 0);
3104         R_SetupShader_SetPermutationGLSL(3, 2048);
3105         R_SetupShader_SetPermutationGLSL(5, 0);
3106         R_SetupShader_SetPermutationGLSL(5, 2);
3107         R_SetupShader_SetPermutationGLSL(5, 2048);
3108         R_SetupShader_SetPermutationGLSL(5, 8388608);
3109         R_SetupShader_SetPermutationGLSL(11, 1);
3110         R_SetupShader_SetPermutationGLSL(11, 2049);
3111         R_SetupShader_SetPermutationGLSL(11, 8193);
3112         R_SetupShader_SetPermutationGLSL(11, 10241);
3113         Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
3114 #endif
3115 }
3116
3117 static void gl_main_shutdown(void)
3118 {
3119         R_RenderTarget_FreeUnused(true);
3120         Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
3121         R_AnimCache_Free();
3122         R_FrameData_Reset();
3123         R_BufferData_Reset();
3124
3125         R_Main_FreeViewCache();
3126
3127         switch(vid.renderpath)
3128         {
3129         case RENDERPATH_GL20:
3130         case RENDERPATH_GLES2:
3131 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
3132                 if (r_maxqueries)
3133                         qglDeleteQueriesARB(r_maxqueries, r_queries);
3134 #endif
3135                 break;
3136         }
3137
3138         r_numqueries = 0;
3139         r_maxqueries = 0;
3140         memset(r_queries, 0, sizeof(r_queries));
3141
3142         r_qwskincache = NULL;
3143         r_qwskincache_size = 0;
3144
3145         // clear out the r_skinframe state
3146         Mem_ExpandableArray_FreeArray(&r_skinframe.array);
3147         memset(&r_skinframe, 0, sizeof(r_skinframe));
3148
3149         if (r_svbsp.nodes)
3150                 Mem_Free(r_svbsp.nodes);
3151         memset(&r_svbsp, 0, sizeof (r_svbsp));
3152         R_FreeTexturePool(&r_main_texturepool);
3153         loadingscreentexture = NULL;
3154         r_texture_blanknormalmap = NULL;
3155         r_texture_white = NULL;
3156         r_texture_grey128 = NULL;
3157         r_texture_black = NULL;
3158         r_texture_whitecube = NULL;
3159         r_texture_normalizationcube = NULL;
3160         r_texture_fogattenuation = NULL;
3161         r_texture_fogheighttexture = NULL;
3162         r_texture_gammaramps = NULL;
3163         r_texture_numcubemaps = 0;
3164         //r_texture_fogintensity = NULL;
3165         memset(&r_fb, 0, sizeof(r_fb));
3166         R_GLSL_Restart_f();
3167
3168         r_glsl_permutation = NULL;
3169         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3170         Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
3171 }
3172
3173 static void gl_main_newmap(void)
3174 {
3175         // FIXME: move this code to client
3176         char *entities, entname[MAX_QPATH];
3177         if (r_qwskincache)
3178                 Mem_Free(r_qwskincache);
3179         r_qwskincache = NULL;
3180         r_qwskincache_size = 0;
3181         if (cl.worldmodel)
3182         {
3183                 dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension);
3184                 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
3185                 {
3186                         CL_ParseEntityLump(entities);
3187                         Mem_Free(entities);
3188                         return;
3189                 }
3190                 if (cl.worldmodel->brush.entities)
3191                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
3192         }
3193         R_Main_FreeViewCache();
3194
3195         R_FrameData_Reset();
3196         R_BufferData_Reset();
3197 }
3198
3199 void GL_Main_Init(void)
3200 {
3201         int i;
3202         r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
3203         R_InitShaderModeInfo();
3204
3205         Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
3206         Cmd_AddCommand("r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
3207         // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
3208         if (gamemode == GAME_NEHAHRA)
3209         {
3210                 Cvar_RegisterVariable (&gl_fogenable);
3211                 Cvar_RegisterVariable (&gl_fogdensity);
3212                 Cvar_RegisterVariable (&gl_fogred);
3213                 Cvar_RegisterVariable (&gl_foggreen);
3214                 Cvar_RegisterVariable (&gl_fogblue);
3215                 Cvar_RegisterVariable (&gl_fogstart);
3216                 Cvar_RegisterVariable (&gl_fogend);
3217                 Cvar_RegisterVariable (&gl_skyclip);
3218         }
3219         Cvar_RegisterVariable(&r_motionblur);
3220         Cvar_RegisterVariable(&r_damageblur);
3221         Cvar_RegisterVariable(&r_motionblur_averaging);
3222         Cvar_RegisterVariable(&r_motionblur_randomize);
3223         Cvar_RegisterVariable(&r_motionblur_minblur);
3224         Cvar_RegisterVariable(&r_motionblur_maxblur);
3225         Cvar_RegisterVariable(&r_motionblur_velocityfactor);
3226         Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed);
3227         Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed);
3228         Cvar_RegisterVariable(&r_motionblur_mousefactor);
3229         Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed);
3230         Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed);
3231         Cvar_RegisterVariable(&r_equalize_entities_fullbright);
3232         Cvar_RegisterVariable(&r_equalize_entities_minambient);
3233         Cvar_RegisterVariable(&r_equalize_entities_by);
3234         Cvar_RegisterVariable(&r_equalize_entities_to);
3235         Cvar_RegisterVariable(&r_depthfirst);
3236         Cvar_RegisterVariable(&r_useinfinitefarclip);
3237         Cvar_RegisterVariable(&r_farclip_base);
3238         Cvar_RegisterVariable(&r_farclip_world);
3239         Cvar_RegisterVariable(&r_nearclip);
3240         Cvar_RegisterVariable(&r_deformvertexes);
3241         Cvar_RegisterVariable(&r_transparent);
3242         Cvar_RegisterVariable(&r_transparent_alphatocoverage);
3243         Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
3244         Cvar_RegisterVariable(&r_transparent_useplanardistance);
3245         Cvar_RegisterVariable(&r_showoverdraw);
3246         Cvar_RegisterVariable(&r_showbboxes);
3247         Cvar_RegisterVariable(&r_showbboxes_client);
3248         Cvar_RegisterVariable(&r_showsurfaces);
3249         Cvar_RegisterVariable(&r_showtris);
3250         Cvar_RegisterVariable(&r_shownormals);
3251         Cvar_RegisterVariable(&r_showlighting);
3252         Cvar_RegisterVariable(&r_showcollisionbrushes);
3253         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
3254         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
3255         Cvar_RegisterVariable(&r_showdisabledepthtest);
3256         Cvar_RegisterVariable(&r_showspriteedges);
3257         Cvar_RegisterVariable(&r_showparticleedges);
3258         Cvar_RegisterVariable(&r_drawportals);
3259         Cvar_RegisterVariable(&r_drawentities);
3260         Cvar_RegisterVariable(&r_draw2d);
3261         Cvar_RegisterVariable(&r_drawworld);
3262         Cvar_RegisterVariable(&r_cullentities_trace);
3263         Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
3264         Cvar_RegisterVariable(&r_cullentities_trace_samples);
3265         Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
3266         Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
3267         Cvar_RegisterVariable(&r_cullentities_trace_expand);
3268         Cvar_RegisterVariable(&r_cullentities_trace_pad);
3269         Cvar_RegisterVariable(&r_cullentities_trace_delay);
3270         Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
3271         Cvar_RegisterVariable(&r_sortentities);
3272         Cvar_RegisterVariable(&r_drawviewmodel);
3273         Cvar_RegisterVariable(&r_drawexteriormodel);
3274         Cvar_RegisterVariable(&r_speeds);
3275         Cvar_RegisterVariable(&r_fullbrights);
3276         Cvar_RegisterVariable(&r_wateralpha);
3277         Cvar_RegisterVariable(&r_dynamic);
3278         Cvar_RegisterVariable(&r_fakelight);
3279         Cvar_RegisterVariable(&r_fakelight_intensity);
3280         Cvar_RegisterVariable(&r_fullbright_directed);
3281         Cvar_RegisterVariable(&r_fullbright_directed_ambient);
3282         Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
3283         Cvar_RegisterVariable(&r_fullbright_directed_pitch);
3284         Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
3285         Cvar_RegisterVariable(&r_fullbright);
3286         Cvar_RegisterVariable(&r_shadows);
3287         Cvar_RegisterVariable(&r_shadows_darken);
3288         Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
3289         Cvar_RegisterVariable(&r_shadows_castfrombmodels);
3290         Cvar_RegisterVariable(&r_shadows_throwdistance);
3291         Cvar_RegisterVariable(&r_shadows_throwdirection);
3292         Cvar_RegisterVariable(&r_shadows_focus);
3293         Cvar_RegisterVariable(&r_shadows_shadowmapscale);
3294         Cvar_RegisterVariable(&r_shadows_shadowmapbias);
3295         Cvar_RegisterVariable(&r_q1bsp_skymasking);
3296         Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
3297         Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
3298         Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
3299         Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
3300         Cvar_RegisterVariable(&r_fog_exp2);
3301         Cvar_RegisterVariable(&r_fog_clear);
3302         Cvar_RegisterVariable(&r_drawfog);
3303         Cvar_RegisterVariable(&r_transparentdepthmasking);
3304         Cvar_RegisterVariable(&r_transparent_sortmindist);
3305         Cvar_RegisterVariable(&r_transparent_sortmaxdist);
3306         Cvar_RegisterVariable(&r_transparent_sortarraysize);
3307         Cvar_RegisterVariable(&r_texture_dds_load);
3308         Cvar_RegisterVariable(&r_texture_dds_save);
3309         Cvar_RegisterVariable(&r_textureunits);
3310         Cvar_RegisterVariable(&gl_combine);
3311         Cvar_RegisterVariable(&r_usedepthtextures);
3312         Cvar_RegisterVariable(&r_viewfbo);
3313         Cvar_RegisterVariable(&r_rendertarget_debug);
3314         Cvar_RegisterVariable(&r_viewscale);
3315         Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3316         Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3317         Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3318         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3319         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3320         Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3321         Cvar_RegisterVariable(&r_glsl);
3322         Cvar_RegisterVariable(&r_glsl_deluxemapping);
3323         Cvar_RegisterVariable(&r_glsl_offsetmapping);
3324         Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3325         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3326         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3327         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3328         Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3329         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3330         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3331         Cvar_RegisterVariable(&r_glsl_postprocess);
3332         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3333         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3334         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3335         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3336         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3337         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3338         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3339         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3340         Cvar_RegisterVariable(&r_celshading);
3341         Cvar_RegisterVariable(&r_celoutlines);
3342
3343         Cvar_RegisterVariable(&r_water);
3344         Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3345         Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3346         Cvar_RegisterVariable(&r_water_clippingplanebias);
3347         Cvar_RegisterVariable(&r_water_refractdistort);
3348         Cvar_RegisterVariable(&r_water_reflectdistort);
3349         Cvar_RegisterVariable(&r_water_scissormode);
3350         Cvar_RegisterVariable(&r_water_lowquality);
3351         Cvar_RegisterVariable(&r_water_hideplayer);
3352
3353         Cvar_RegisterVariable(&r_lerpsprites);
3354         Cvar_RegisterVariable(&r_lerpmodels);
3355         Cvar_RegisterVariable(&r_lerplightstyles);
3356         Cvar_RegisterVariable(&r_waterscroll);
3357         Cvar_RegisterVariable(&r_bloom);
3358         Cvar_RegisterVariable(&r_bloom_colorscale);
3359         Cvar_RegisterVariable(&r_bloom_brighten);
3360         Cvar_RegisterVariable(&r_bloom_blur);
3361         Cvar_RegisterVariable(&r_bloom_resolution);
3362         Cvar_RegisterVariable(&r_bloom_colorexponent);
3363         Cvar_RegisterVariable(&r_bloom_colorsubtract);
3364         Cvar_RegisterVariable(&r_bloom_scenebrightness);
3365         Cvar_RegisterVariable(&r_hdr_scenebrightness);
3366         Cvar_RegisterVariable(&r_hdr_glowintensity);
3367         Cvar_RegisterVariable(&r_hdr_irisadaptation);
3368         Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3369         Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3370         Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3371         Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3372         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3373         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3374         Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3375         Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3376         Cvar_RegisterVariable(&developer_texturelogging);
3377         Cvar_RegisterVariable(&gl_lightmaps);
3378         Cvar_RegisterVariable(&r_test);
3379         Cvar_RegisterVariable(&r_batch_multidraw);
3380         Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3381         Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3382         Cvar_RegisterVariable(&r_glsl_skeletal);
3383         Cvar_RegisterVariable(&r_glsl_saturation);
3384         Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3385         Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3386         Cvar_RegisterVariable(&r_framedatasize);
3387         for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3388                 Cvar_RegisterVariable(&r_buffermegs[i]);
3389         Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3390         if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3391                 Cvar_SetValue("r_fullbrights", 0);
3392 #ifdef DP_MOBILETOUCH
3393         // GLES devices have terrible depth precision in general, so...
3394         Cvar_SetValueQuick(&r_nearclip, 4);
3395         Cvar_SetValueQuick(&r_farclip_base, 4096);
3396         Cvar_SetValueQuick(&r_farclip_world, 0);
3397         Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3398 #endif
3399         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3400 }
3401
3402 void Render_Init(void)
3403 {
3404         gl_backend_init();
3405         R_Textures_Init();
3406         GL_Main_Init();
3407         Font_Init();
3408         GL_Draw_Init();
3409         R_Shadow_Init();
3410         R_Sky_Init();
3411         GL_Surf_Init();
3412         Sbar_Init();
3413         R_Particles_Init();
3414         R_Explosion_Init();
3415         R_LightningBeams_Init();
3416         Mod_RenderInit();
3417 }
3418
3419 /*
3420 ===============
3421 GL_Init
3422 ===============
3423 */
3424 #ifndef USE_GLES2
3425 extern char *ENGINE_EXTENSIONS;
3426 void GL_Init (void)
3427 {
3428         gl_renderer = (const char *)qglGetString(GL_RENDERER);
3429         gl_vendor = (const char *)qglGetString(GL_VENDOR);
3430         gl_version = (const char *)qglGetString(GL_VERSION);
3431         gl_extensions = (const char *)qglGetString(GL_EXTENSIONS);
3432
3433         if (!gl_extensions)
3434                 gl_extensions = "";
3435         if (!gl_platformextensions)
3436                 gl_platformextensions = "";
3437
3438         Con_Printf("GL_VENDOR: %s\n", gl_vendor);
3439         Con_Printf("GL_RENDERER: %s\n", gl_renderer);
3440         Con_Printf("GL_VERSION: %s\n", gl_version);
3441         Con_DPrintf("GL_EXTENSIONS: %s\n", gl_extensions);
3442         Con_DPrintf("%s_EXTENSIONS: %s\n", gl_platform, gl_platformextensions);
3443
3444         VID_CheckExtensions();
3445
3446         // LordHavoc: report supported extensions
3447 #ifdef CONFIG_MENU
3448         Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions );
3449 #else
3450         Con_DPrintf("\nQuakeC extensions for server and client: %s\n", vm_sv_extensions );
3451 #endif
3452
3453         // clear to black (loading plaque will be seen over this)
3454         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0);
3455 }
3456 #endif
3457
3458 int R_CullBox(const vec3_t mins, const vec3_t maxs)
3459 {
3460         int i;
3461         mplane_t *p;
3462         if (r_trippy.integer)
3463                 return false;
3464         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
3465         {
3466                 p = r_refdef.view.frustum + i;
3467                 switch(p->signbits)
3468                 {
3469                 default:
3470                 case 0:
3471                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3472                                 return true;
3473                         break;
3474                 case 1:
3475                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3476                                 return true;
3477                         break;
3478                 case 2:
3479                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3480                                 return true;
3481                         break;
3482                 case 3:
3483                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3484                                 return true;
3485                         break;
3486                 case 4:
3487                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3488                                 return true;
3489                         break;
3490                 case 5:
3491                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3492                                 return true;
3493                         break;
3494                 case 6:
3495                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3496                                 return true;
3497                         break;
3498                 case 7:
3499                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3500                                 return true;
3501                         break;
3502                 }
3503         }
3504         return false;
3505 }
3506
3507 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3508 {
3509         int i;
3510         const mplane_t *p;
3511         if (r_trippy.integer)
3512                 return false;
3513         for (i = 0;i < numplanes;i++)
3514         {
3515                 p = planes + i;
3516                 switch(p->signbits)
3517                 {
3518                 default:
3519                 case 0:
3520                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3521                                 return true;
3522                         break;
3523                 case 1:
3524                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3525                                 return true;
3526                         break;
3527                 case 2:
3528                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3529                                 return true;
3530                         break;
3531                 case 3:
3532                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3533                                 return true;
3534                         break;
3535                 case 4:
3536                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3537                                 return true;
3538                         break;
3539                 case 5:
3540                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3541                                 return true;
3542                         break;
3543                 case 6:
3544                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3545                                 return true;
3546                         break;
3547                 case 7:
3548                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3549                                 return true;
3550                         break;
3551                 }
3552         }
3553         return false;
3554 }
3555
3556 //==================================================================================
3557
3558 // LordHavoc: this stores temporary data used within the same frame
3559
3560 typedef struct r_framedata_mem_s
3561 {
3562         struct r_framedata_mem_s *purge; // older mem block to free on next frame
3563         size_t size; // how much usable space
3564         size_t current; // how much space in use
3565         size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3566         size_t wantedsize; // how much space was allocated
3567         unsigned char *data; // start of real data (16byte aligned)
3568 }
3569 r_framedata_mem_t;
3570
3571 static r_framedata_mem_t *r_framedata_mem;
3572
3573 void R_FrameData_Reset(void)
3574 {
3575         while (r_framedata_mem)
3576         {
3577                 r_framedata_mem_t *next = r_framedata_mem->purge;
3578                 Mem_Free(r_framedata_mem);
3579                 r_framedata_mem = next;
3580         }
3581 }
3582
3583 static void R_FrameData_Resize(qboolean mustgrow)
3584 {
3585         size_t wantedsize;
3586         wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3587         wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3588         if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3589         {
3590                 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3591                 newmem->wantedsize = wantedsize;
3592                 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3593                 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3594                 newmem->current = 0;
3595                 newmem->mark = 0;
3596                 newmem->purge = r_framedata_mem;
3597                 r_framedata_mem = newmem;
3598         }
3599 }
3600
3601 void R_FrameData_NewFrame(void)
3602 {
3603         R_FrameData_Resize(false);
3604         if (!r_framedata_mem)
3605                 return;
3606         // if we ran out of space on the last frame, free the old memory now
3607         while (r_framedata_mem->purge)
3608         {
3609                 // repeatedly remove the second item in the list, leaving only head
3610                 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3611                 Mem_Free(r_framedata_mem->purge);
3612                 r_framedata_mem->purge = next;
3613         }
3614         // reset the current mem pointer
3615         r_framedata_mem->current = 0;
3616         r_framedata_mem->mark = 0;
3617 }
3618
3619 void *R_FrameData_Alloc(size_t size)
3620 {
3621         void *data;
3622         float newvalue;
3623
3624         // align to 16 byte boundary - the data pointer is already aligned, so we
3625         // only need to ensure the size of every allocation is also aligned
3626         size = (size + 15) & ~15;
3627
3628         while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3629         {
3630                 // emergency - we ran out of space, allocate more memory
3631                 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3632                 newvalue = r_framedatasize.value * 2.0f;
3633                 // 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
3634                 if (sizeof(size_t) >= 8)
3635                         newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3636                 else
3637                         newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3638                 // this might not be a growing it, but we'll allocate another buffer every time
3639                 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3640                 R_FrameData_Resize(true);
3641         }
3642
3643         data = r_framedata_mem->data + r_framedata_mem->current;
3644         r_framedata_mem->current += size;
3645
3646         // count the usage for stats
3647         r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3648         r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3649
3650         return (void *)data;
3651 }
3652
3653 void *R_FrameData_Store(size_t size, void *data)
3654 {
3655         void *d = R_FrameData_Alloc(size);
3656         if (d && data)
3657                 memcpy(d, data, size);
3658         return d;
3659 }
3660
3661 void R_FrameData_SetMark(void)
3662 {
3663         if (!r_framedata_mem)
3664                 return;
3665         r_framedata_mem->mark = r_framedata_mem->current;
3666 }
3667
3668 void R_FrameData_ReturnToMark(void)
3669 {
3670         if (!r_framedata_mem)
3671                 return;
3672         r_framedata_mem->current = r_framedata_mem->mark;
3673 }
3674
3675 //==================================================================================
3676
3677 // avoid reusing the same buffer objects on consecutive frames
3678 #define R_BUFFERDATA_CYCLE 3
3679
3680 typedef struct r_bufferdata_buffer_s
3681 {
3682         struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3683         size_t size; // how much usable space
3684         size_t current; // how much space in use
3685         r_meshbuffer_t *buffer; // the buffer itself
3686 }
3687 r_bufferdata_buffer_t;
3688
3689 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3690 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3691
3692 /// frees all dynamic buffers
3693 void R_BufferData_Reset(void)
3694 {
3695         int cycle, type;
3696         r_bufferdata_buffer_t **p, *mem;
3697         for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3698         {
3699                 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3700                 {
3701                         // free all buffers
3702                         p = &r_bufferdata_buffer[cycle][type];
3703                         while (*p)
3704                         {
3705                                 mem = *p;
3706                                 *p = (*p)->purge;
3707                                 if (mem->buffer)
3708                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3709                                 Mem_Free(mem);
3710                         }
3711                 }
3712         }
3713 }
3714
3715 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3716 static void R_BufferData_Resize(r_bufferdata_type_t type, qboolean mustgrow, size_t minsize)
3717 {
3718         r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3719         size_t size;
3720         float newvalue = r_buffermegs[type].value;
3721
3722         // increase the cvar if we have to (but only if we already have a mem)
3723         if (mustgrow && mem)
3724                 newvalue *= 2.0f;
3725         newvalue = bound(0.25f, newvalue, 256.0f);
3726         while (newvalue * 1024*1024 < minsize)
3727                 newvalue *= 2.0f;
3728
3729         // clamp the cvar to valid range
3730         newvalue = bound(0.25f, newvalue, 256.0f);
3731         if (r_buffermegs[type].value != newvalue)
3732                 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3733
3734         // calculate size in bytes
3735         size = (size_t)(newvalue * 1024*1024);
3736         size = bound(131072, size, 256*1024*1024);
3737
3738         // allocate a new buffer if the size is different (purge old one later)
3739         // or if we were told we must grow the buffer
3740         if (!mem || mem->size != size || mustgrow)
3741         {
3742                 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3743                 mem->size = size;
3744                 mem->current = 0;
3745                 if (type == R_BUFFERDATA_VERTEX)
3746                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3747                 else if (type == R_BUFFERDATA_INDEX16)
3748                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3749                 else if (type == R_BUFFERDATA_INDEX32)
3750                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3751                 else if (type == R_BUFFERDATA_UNIFORM)
3752                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3753                 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3754                 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3755         }
3756 }
3757
3758 void R_BufferData_NewFrame(void)
3759 {
3760         int type;
3761         r_bufferdata_buffer_t **p, *mem;
3762         // cycle to the next frame's buffers
3763         r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3764         // if we ran out of space on the last time we used these buffers, free the old memory now
3765         for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3766         {
3767                 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3768                 {
3769                         R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3770                         // free all but the head buffer, this is how we recycle obsolete
3771                         // buffers after they are no longer in use
3772                         p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3773                         while (*p)
3774                         {
3775                                 mem = *p;
3776                                 *p = (*p)->purge;
3777                                 if (mem->buffer)
3778                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3779                                 Mem_Free(mem);
3780                         }
3781                         // reset the current offset
3782                         r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3783                 }
3784         }
3785 }
3786
3787 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3788 {
3789         r_bufferdata_buffer_t *mem;
3790         int offset = 0;
3791         int padsize;
3792
3793         *returnbufferoffset = 0;
3794
3795         // align size to a byte boundary appropriate for the buffer type, this
3796         // makes all allocations have aligned start offsets
3797         if (type == R_BUFFERDATA_UNIFORM)
3798                 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3799         else
3800                 padsize = (datasize + 15) & ~15;
3801
3802         // if we ran out of space in this buffer we must allocate a new one
3803         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)
3804                 R_BufferData_Resize(type, true, padsize);
3805
3806         // if the resize did not give us enough memory, fail
3807         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)
3808                 Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3809
3810         mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3811         offset = (int)mem->current;
3812         mem->current += padsize;
3813
3814         // upload the data to the buffer at the chosen offset
3815         if (offset == 0)
3816                 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3817         R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3818
3819         // count the usage for stats
3820         r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3821         r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3822
3823         // return the buffer offset
3824         *returnbufferoffset = offset;
3825
3826         return mem->buffer;
3827 }
3828
3829 //==================================================================================
3830
3831 // LordHavoc: animcache originally written by Echon, rewritten since then
3832
3833 /**
3834  * Animation cache prevents re-generating mesh data for an animated model
3835  * multiple times in one frame for lighting, shadowing, reflections, etc.
3836  */
3837
3838 void R_AnimCache_Free(void)
3839 {
3840 }
3841
3842 void R_AnimCache_ClearCache(void)
3843 {
3844         int i;
3845         entity_render_t *ent;
3846
3847         for (i = 0;i < r_refdef.scene.numentities;i++)
3848         {
3849                 ent = r_refdef.scene.entities[i];
3850                 ent->animcache_vertex3f = NULL;
3851                 ent->animcache_vertex3f_vertexbuffer = NULL;
3852                 ent->animcache_vertex3f_bufferoffset = 0;
3853                 ent->animcache_normal3f = NULL;
3854                 ent->animcache_normal3f_vertexbuffer = NULL;
3855                 ent->animcache_normal3f_bufferoffset = 0;
3856                 ent->animcache_svector3f = NULL;
3857                 ent->animcache_svector3f_vertexbuffer = NULL;
3858                 ent->animcache_svector3f_bufferoffset = 0;
3859                 ent->animcache_tvector3f = NULL;
3860                 ent->animcache_tvector3f_vertexbuffer = NULL;
3861                 ent->animcache_tvector3f_bufferoffset = 0;
3862                 ent->animcache_skeletaltransform3x4 = NULL;
3863                 ent->animcache_skeletaltransform3x4buffer = NULL;
3864                 ent->animcache_skeletaltransform3x4offset = 0;
3865                 ent->animcache_skeletaltransform3x4size = 0;
3866         }
3867 }
3868
3869 qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
3870 {
3871         dp_model_t *model = ent->model;
3872         int numvertices;
3873
3874         // see if this ent is worth caching
3875         if (!model || !model->Draw || !model->AnimateVertices)
3876                 return false;
3877         // nothing to cache if it contains no animations and has no skeleton
3878         if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3879                 return false;
3880         // see if it is already cached for gpuskeletal
3881         if (ent->animcache_skeletaltransform3x4)
3882                 return false;
3883         // see if it is already cached as a mesh
3884         if (ent->animcache_vertex3f)
3885         {
3886                 // check if we need to add normals or tangents
3887                 if (ent->animcache_normal3f)
3888                         wantnormals = false;
3889                 if (ent->animcache_svector3f)
3890                         wanttangents = false;
3891                 if (!wantnormals && !wanttangents)
3892                         return false;
3893         }
3894
3895         // check which kind of cache we need to generate
3896         if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3897         {
3898                 // cache the skeleton so the vertex shader can use it
3899                 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3900                 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3901                 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3902                 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3903                 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4); 
3904                 // note: this can fail if the buffer is at the grow limit
3905                 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3906                 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3907         }
3908         else if (ent->animcache_vertex3f)
3909         {
3910                 // mesh was already cached but we may need to add normals/tangents
3911                 // (this only happens with multiple views, reflections, cameras, etc)
3912                 if (wantnormals || wanttangents)
3913                 {
3914                         numvertices = model->surfmesh.num_vertices;
3915                         if (wantnormals)
3916                                 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3917                         if (wanttangents)
3918                         {
3919                                 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3920                                 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3921                         }
3922                         model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3923                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3924                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3925                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3926                 }
3927         }
3928         else
3929         {
3930                 // generate mesh cache
3931                 numvertices = model->surfmesh.num_vertices;
3932                 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3933                 if (wantnormals)
3934                         ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3935                 if (wanttangents)
3936                 {
3937                         ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3938                         ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3939                 }
3940                 model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
3941                 if (wantnormals || wanttangents)
3942                 {
3943                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3944                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3945                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3946                 }
3947                 r_refdef.stats[r_stat_animcache_shape_count] += 1;
3948                 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
3949                 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
3950         }
3951         return true;
3952 }
3953
3954 void R_AnimCache_CacheVisibleEntities(void)
3955 {
3956         int i;
3957
3958         // TODO: thread this
3959         // NOTE: R_PrepareRTLights() also caches entities
3960
3961         for (i = 0;i < r_refdef.scene.numentities;i++)
3962                 if (r_refdef.viewcache.entityvisible[i])
3963                         R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
3964 }
3965
3966 //==================================================================================
3967
3968 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)
3969 {
3970         int i;
3971         vec3_t eyemins, eyemaxs;
3972         vec3_t boxmins, boxmaxs;
3973         vec3_t padmins, padmaxs;
3974         vec3_t start;
3975         vec3_t end;
3976         dp_model_t *model = r_refdef.scene.worldmodel;
3977         static vec3_t positions[] = {
3978                 { 0.5f, 0.5f, 0.5f },
3979                 { 0.0f, 0.0f, 0.0f },
3980                 { 0.0f, 0.0f, 1.0f },
3981                 { 0.0f, 1.0f, 0.0f },
3982                 { 0.0f, 1.0f, 1.0f },
3983                 { 1.0f, 0.0f, 0.0f },
3984                 { 1.0f, 0.0f, 1.0f },
3985                 { 1.0f, 1.0f, 0.0f },
3986                 { 1.0f, 1.0f, 1.0f },
3987         };
3988
3989         // sample count can be set to -1 to skip this logic, for flicker-prone objects
3990         if (numsamples < 0)
3991                 return true;
3992
3993         // view origin is not used for culling in portal/reflection/refraction renders or isometric views
3994         if (!r_refdef.view.usevieworiginculling)
3995                 return true;
3996
3997         if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
3998                 return true;
3999
4000         // expand the eye box a little
4001         eyemins[0] = eye[0] - eyejitter;
4002         eyemaxs[0] = eye[0] + eyejitter;
4003         eyemins[1] = eye[1] - eyejitter;
4004         eyemaxs[1] = eye[1] + eyejitter;
4005         eyemins[2] = eye[2] - eyejitter;
4006         eyemaxs[2] = eye[2] + eyejitter;
4007         // expand the box a little
4008         boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
4009         boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
4010         boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
4011         boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
4012         boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
4013         boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
4014         // make an even larger box for the acceptable area
4015         padmins[0] = boxmins[0] - pad;
4016         padmaxs[0] = boxmaxs[0] + pad;
4017         padmins[1] = boxmins[1] - pad;
4018         padmaxs[1] = boxmaxs[1] + pad;
4019         padmins[2] = boxmins[2] - pad;
4020         padmaxs[2] = boxmaxs[2] + pad;
4021
4022         // return true if eye overlaps enlarged box
4023         if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
4024                 return true;
4025
4026         // try specific positions in the box first - note that these can be cached
4027         if (r_cullentities_trace_entityocclusion.integer)
4028         {
4029                 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
4030                 {
4031                         VectorCopy(eye, start);
4032                         end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
4033                         end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
4034                         end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
4035                         //trace_t trace = CL_TraceLine(start, end, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, 0.0f, true, false, NULL, true, true);
4036                         trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
4037                         // not picky - if the trace ended anywhere in the box we're good
4038                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4039                                 return true;
4040                 }
4041         }
4042         else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4043                 return true;
4044
4045         // try various random positions
4046         for (i = 0; i < numsamples; i++)
4047         {
4048                 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
4049                 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
4050                 if (r_cullentities_trace_entityocclusion.integer)
4051                 {
4052                         trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
4053                         // not picky - if the trace ended anywhere in the box we're good
4054                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4055                                 return true;
4056                 }
4057                 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4058                         return true;
4059         }
4060
4061         return false;
4062 }
4063
4064
4065 static void R_View_UpdateEntityVisible (void)
4066 {
4067         int i;
4068         int renderimask;
4069         int samples;
4070         entity_render_t *ent;
4071
4072         if (r_refdef.envmap || r_fb.water.hideplayer)
4073                 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
4074         else if (chase_active.integer || r_fb.water.renderingscene)
4075                 renderimask = RENDER_VIEWMODEL;
4076         else
4077                 renderimask = RENDER_EXTERIORMODEL;
4078         if (!r_drawviewmodel.integer)
4079                 renderimask |= RENDER_VIEWMODEL;
4080         if (!r_drawexteriormodel.integer)
4081                 renderimask |= RENDER_EXTERIORMODEL;
4082         memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4083         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4084         {
4085                 // worldmodel can check visibility
4086                 for (i = 0;i < r_refdef.scene.numentities;i++)
4087                 {
4088                         ent = r_refdef.scene.entities[i];
4089                         if (!(ent->flags & renderimask))
4090                         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)))
4091                         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))
4092                                 r_refdef.viewcache.entityvisible[i] = true;
4093                 }
4094         }
4095         else
4096         {
4097                 // no worldmodel or it can't check visibility
4098                 for (i = 0;i < r_refdef.scene.numentities;i++)
4099                 {
4100                         ent = r_refdef.scene.entities[i];
4101                         if (!(ent->flags & renderimask))
4102                         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)))
4103                                 r_refdef.viewcache.entityvisible[i] = true;
4104                 }
4105         }
4106         if (r_cullentities_trace.integer)
4107         {
4108                 for (i = 0;i < r_refdef.scene.numentities;i++)
4109                 {
4110                         if (!r_refdef.viewcache.entityvisible[i])
4111                                 continue;
4112                         ent = r_refdef.scene.entities[i];
4113                         if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4114                         {
4115                                 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4116                                 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))
4117                                         ent->last_trace_visibility = realtime;
4118                                 if (ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
4119                                         r_refdef.viewcache.entityvisible[i] = 0;
4120                         }
4121                 }
4122         }
4123 }
4124
4125 /// only used if skyrendermasked, and normally returns false
4126 static int R_DrawBrushModelsSky (void)
4127 {
4128         int i, sky;
4129         entity_render_t *ent;
4130
4131         sky = false;
4132         for (i = 0;i < r_refdef.scene.numentities;i++)
4133         {
4134                 if (!r_refdef.viewcache.entityvisible[i])
4135                         continue;
4136                 ent = r_refdef.scene.entities[i];
4137                 if (!ent->model || !ent->model->DrawSky)
4138                         continue;
4139                 ent->model->DrawSky(ent);
4140                 sky = true;
4141         }
4142         return sky;
4143 }
4144
4145 static void R_DrawNoModel(entity_render_t *ent);
4146 static void R_DrawModels(void)
4147 {
4148         int i;
4149         entity_render_t *ent;
4150
4151         for (i = 0;i < r_refdef.scene.numentities;i++)
4152         {
4153                 if (!r_refdef.viewcache.entityvisible[i])
4154                         continue;
4155                 ent = r_refdef.scene.entities[i];
4156                 r_refdef.stats[r_stat_entities]++;
4157                 /*
4158                 if (ent->model && !strncmp(ent->model->name, "models/proto_", 13))
4159                 {
4160                         vec3_t f, l, u, o;
4161                         Matrix4x4_ToVectors(&ent->matrix, f, l, u, o);
4162                         Con_Printf("R_DrawModels\n");
4163                         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]);
4164                         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);
4165                         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);
4166                 }
4167                 */
4168                 if (ent->model && ent->model->Draw != NULL)
4169                         ent->model->Draw(ent);
4170                 else
4171                         R_DrawNoModel(ent);
4172         }
4173 }
4174
4175 static void R_DrawModelsDepth(void)
4176 {
4177         int i;
4178         entity_render_t *ent;
4179
4180         for (i = 0;i < r_refdef.scene.numentities;i++)
4181         {
4182                 if (!r_refdef.viewcache.entityvisible[i])
4183                         continue;
4184                 ent = r_refdef.scene.entities[i];
4185                 if (ent->model && ent->model->DrawDepth != NULL)
4186                         ent->model->DrawDepth(ent);
4187         }
4188 }
4189
4190 static void R_DrawModelsDebug(void)
4191 {
4192         int i;
4193         entity_render_t *ent;
4194
4195         for (i = 0;i < r_refdef.scene.numentities;i++)
4196         {
4197                 if (!r_refdef.viewcache.entityvisible[i])
4198                         continue;
4199                 ent = r_refdef.scene.entities[i];
4200                 if (ent->model && ent->model->DrawDebug != NULL)
4201                         ent->model->DrawDebug(ent);
4202         }
4203 }
4204
4205 static void R_DrawModelsAddWaterPlanes(void)
4206 {
4207         int i;
4208         entity_render_t *ent;
4209
4210         for (i = 0;i < r_refdef.scene.numentities;i++)
4211         {
4212                 if (!r_refdef.viewcache.entityvisible[i])
4213                         continue;
4214                 ent = r_refdef.scene.entities[i];
4215                 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4216                         ent->model->DrawAddWaterPlanes(ent);
4217         }
4218 }
4219
4220 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}};
4221
4222 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4223 {
4224         if (r_hdr_irisadaptation.integer)
4225         {
4226                 vec3_t p;
4227                 vec3_t ambient;
4228                 vec3_t diffuse;
4229                 vec3_t diffusenormal;
4230                 vec3_t forward;
4231                 vec_t brightness = 0.0f;
4232                 vec_t goal;
4233                 vec_t current;
4234                 vec_t d;
4235                 int c;
4236                 VectorCopy(r_refdef.view.forward, forward);
4237                 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4238                 {
4239                         p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4240                         p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4241                         p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4242                         R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4243                         d = DotProduct(forward, diffusenormal);
4244                         brightness += VectorLength(ambient);
4245                         if (d > 0)
4246                                 brightness += d * VectorLength(diffuse);
4247                 }
4248                 brightness *= 1.0f / c;
4249                 brightness += 0.00001f; // make sure it's never zero
4250                 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4251                 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4252                 current = r_hdr_irisadaptation_value.value;
4253                 if (current < goal)
4254                         current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4255                 else if (current > goal)
4256                         current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4257                 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4258                         Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4259         }
4260         else if (r_hdr_irisadaptation_value.value != 1.0f)
4261                 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4262 }
4263
4264 static void R_View_SetFrustum(const int *scissor)
4265 {
4266         int i;
4267         double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4268         vec3_t forward, left, up, origin, v;
4269
4270         if(scissor)
4271         {
4272                 // flipped x coordinates (because x points left here)
4273                 fpx =  1.0 - 2.0 * (scissor[0]              - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4274                 fnx =  1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4275                 // non-flipped y coordinates
4276                 fny = -1.0 + 2.0 * (scissor[1]              - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4277                 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4278         }
4279
4280         // we can't trust r_refdef.view.forward and friends in reflected scenes
4281         Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4282
4283 #if 0
4284         r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4285         r_refdef.view.frustum[0].normal[1] = 0 - 0;
4286         r_refdef.view.frustum[0].normal[2] = -1 - 0;
4287         r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4288         r_refdef.view.frustum[1].normal[1] = 0 + 0;
4289         r_refdef.view.frustum[1].normal[2] = -1 + 0;
4290         r_refdef.view.frustum[2].normal[0] = 0 - 0;
4291         r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4292         r_refdef.view.frustum[2].normal[2] = -1 - 0;
4293         r_refdef.view.frustum[3].normal[0] = 0 + 0;
4294         r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4295         r_refdef.view.frustum[3].normal[2] = -1 + 0;
4296 #endif
4297
4298 #if 0
4299         zNear = r_refdef.nearclip;
4300         nudge = 1.0 - 1.0 / (1<<23);
4301         r_refdef.view.frustum[4].normal[0] = 0 - 0;
4302         r_refdef.view.frustum[4].normal[1] = 0 - 0;
4303         r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4304         r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4305         r_refdef.view.frustum[5].normal[0] = 0 + 0;
4306         r_refdef.view.frustum[5].normal[1] = 0 + 0;
4307         r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4308         r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4309 #endif
4310
4311
4312
4313 #if 0
4314         r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4315         r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4316         r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4317         r_refdef.view.frustum[0].dist = m[15] - m[12];
4318
4319         r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4320         r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4321         r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4322         r_refdef.view.frustum[1].dist = m[15] + m[12];
4323
4324         r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4325         r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4326         r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4327         r_refdef.view.frustum[2].dist = m[15] - m[13];
4328
4329         r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4330         r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4331         r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4332         r_refdef.view.frustum[3].dist = m[15] + m[13];
4333
4334         r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4335         r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4336         r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4337         r_refdef.view.frustum[4].dist = m[15] - m[14];
4338
4339         r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4340         r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4341         r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4342         r_refdef.view.frustum[5].dist = m[15] + m[14];
4343 #endif
4344
4345         if (r_refdef.view.useperspective)
4346         {
4347                 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4348                 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]);
4349                 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]);
4350                 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]);
4351                 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]);
4352
4353                 // then the normals from the corners relative to origin
4354                 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4355                 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4356                 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4357                 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4358
4359                 // in a NORMAL view, forward cross left == up
4360                 // in a REFLECTED view, forward cross left == down
4361                 // so our cross products above need to be adjusted for a left handed coordinate system
4362                 CrossProduct(forward, left, v);
4363                 if(DotProduct(v, up) < 0)
4364                 {
4365                         VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4366                         VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4367                         VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4368                         VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4369                 }
4370
4371                 // Leaving those out was a mistake, those were in the old code, and they
4372                 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4373                 // I couldn't reproduce it after adding those normalizations. --blub
4374                 VectorNormalize(r_refdef.view.frustum[0].normal);
4375                 VectorNormalize(r_refdef.view.frustum[1].normal);
4376                 VectorNormalize(r_refdef.view.frustum[2].normal);
4377                 VectorNormalize(r_refdef.view.frustum[3].normal);
4378
4379                 // make the corners absolute
4380                 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4381                 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4382                 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4383                 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4384
4385                 // one more normal
4386                 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4387
4388                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4389                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4390                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4391                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4392                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4393         }
4394         else
4395         {
4396                 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4397                 VectorScale(left,  1.0f, r_refdef.view.frustum[1].normal);
4398                 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4399                 VectorScale(up,  1.0f, r_refdef.view.frustum[3].normal);
4400                 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4401                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4402                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4403                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4404                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4405                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4406         }
4407         r_refdef.view.numfrustumplanes = 5;
4408
4409         if (r_refdef.view.useclipplane)
4410         {
4411                 r_refdef.view.numfrustumplanes = 6;
4412                 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4413         }
4414
4415         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4416                 PlaneClassify(r_refdef.view.frustum + i);
4417
4418         // LordHavoc: note to all quake engine coders, Quake had a special case
4419         // for 90 degrees which assumed a square view (wrong), so I removed it,
4420         // Quake2 has it disabled as well.
4421
4422         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4423         //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4424         //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4425         //PlaneClassify(&frustum[0]);
4426
4427         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4428         //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4429         //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4430         //PlaneClassify(&frustum[1]);
4431
4432         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4433         //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4434         //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4435         //PlaneClassify(&frustum[2]);
4436
4437         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4438         //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4439         //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4440         //PlaneClassify(&frustum[3]);
4441
4442         // nearclip plane
4443         //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4444         //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4445         //PlaneClassify(&frustum[4]);
4446 }
4447
4448 static void R_View_UpdateWithScissor(const int *myscissor)
4449 {
4450         R_Main_ResizeViewCache();
4451         R_View_SetFrustum(myscissor);
4452         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4453         R_View_UpdateEntityVisible();
4454 }
4455
4456 static void R_View_Update(void)
4457 {
4458         R_Main_ResizeViewCache();
4459         R_View_SetFrustum(NULL);
4460         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4461         R_View_UpdateEntityVisible();
4462 }
4463
4464 float viewscalefpsadjusted = 1.0f;
4465
4466 static void R_GetScaledViewSize(int width, int height, int *outwidth, int *outheight)
4467 {
4468         float scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
4469         scale = bound(0.03125f, scale, 1.0f);
4470         *outwidth = (int)ceil(width * scale);
4471         *outheight = (int)ceil(height * scale);
4472 }
4473
4474 void R_SetupView(qboolean allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4475 {
4476         const float *customclipplane = NULL;
4477         float plane[4];
4478         int /*rtwidth,*/ rtheight;
4479         if (r_refdef.view.useclipplane && allowwaterclippingplane)
4480         {
4481                 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4482                 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4483                 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4484                 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4485                         dist = r_refdef.view.clipplane.dist;
4486                 plane[0] = r_refdef.view.clipplane.normal[0];
4487                 plane[1] = r_refdef.view.clipplane.normal[1];
4488                 plane[2] = r_refdef.view.clipplane.normal[2];
4489                 plane[3] = -dist;
4490                 customclipplane = plane;
4491         }
4492
4493         //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
4494         rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
4495
4496         if (!r_refdef.view.useperspective)
4497                 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);
4498         else if (vid.stencil && r_useinfinitefarclip.integer)
4499                 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);
4500         else
4501                 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);
4502         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4503         R_SetViewport(&r_refdef.view.viewport);
4504 }
4505
4506 void R_EntityMatrix(const matrix4x4_t *matrix)
4507 {
4508         if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4509         {
4510                 gl_modelmatrixchanged = false;
4511                 gl_modelmatrix = *matrix;
4512                 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4513                 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4514                 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4515                 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4516                 CHECKGLERROR
4517                 switch(vid.renderpath)
4518                 {
4519                 case RENDERPATH_GL20:
4520                 case RENDERPATH_GLES2:
4521                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4522                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4523                         break;
4524                 }
4525         }
4526 }
4527
4528 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4529 {
4530         r_viewport_t viewport;
4531
4532         CHECKGLERROR
4533
4534         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
4535         R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4536         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4537         R_SetViewport(&viewport);
4538         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4539         GL_Color(1, 1, 1, 1);
4540         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4541         GL_BlendFunc(GL_ONE, GL_ZERO);
4542         GL_ScissorTest(false);
4543         GL_DepthMask(false);
4544         GL_DepthRange(0, 1);
4545         GL_DepthTest(false);
4546         GL_DepthFunc(GL_LEQUAL);
4547         R_EntityMatrix(&identitymatrix);
4548         R_Mesh_ResetTextureState();
4549         GL_PolygonOffset(0, 0);
4550         switch(vid.renderpath)
4551         {
4552         case RENDERPATH_GL20:
4553         case RENDERPATH_GLES2:
4554                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4555                 break;
4556         }
4557         GL_CullFace(GL_NONE);
4558
4559         CHECKGLERROR
4560 }
4561
4562 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4563 {
4564         R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4565 }
4566
4567 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4568 {
4569         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4570         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4571         GL_Color(1, 1, 1, 1);
4572         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4573         GL_BlendFunc(GL_ONE, GL_ZERO);
4574         GL_ScissorTest(true);
4575         GL_DepthMask(true);
4576         GL_DepthRange(0, 1);
4577         GL_DepthTest(true);
4578         GL_DepthFunc(GL_LEQUAL);
4579         R_EntityMatrix(&identitymatrix);
4580         R_Mesh_ResetTextureState();
4581         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4582         switch(vid.renderpath)
4583         {
4584         case RENDERPATH_GL20:
4585         case RENDERPATH_GLES2:
4586                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4587                 break;
4588         }
4589         GL_CullFace(r_refdef.view.cullface_back);
4590 }
4591
4592 /*
4593 ================
4594 R_RenderView_UpdateViewVectors
4595 ================
4596 */
4597 void R_RenderView_UpdateViewVectors(void)
4598 {
4599         // break apart the view matrix into vectors for various purposes
4600         // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4601         // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4602         Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4603         VectorNegate(r_refdef.view.left, r_refdef.view.right);
4604         // make an inverted copy of the view matrix for tracking sprites
4605         Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4606 }
4607
4608 void R_RenderTarget_FreeUnused(qboolean force)
4609 {
4610         int i, j, end;
4611         end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
4612         for (i = 0; i < end; i++)
4613         {
4614                 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4615                 // free resources for rendertargets that have not been used for a while
4616                 // (note: this check is run after the frame render, so any targets used
4617                 // this frame will not be affected even at low framerates)
4618                 if (r && (realtime - r->lastusetime > 0.2 || force))
4619                 {
4620                         if (r->fbo)
4621                                 R_Mesh_DestroyFramebufferObject(r->fbo);
4622                         for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4623                                 if (r->colortexture[j])
4624                                         R_FreeTexture(r->colortexture[j]);
4625                         if (r->depthtexture)
4626                                 R_FreeTexture(r->depthtexture);
4627                         Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4628                 }
4629         }
4630 }
4631
4632 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4633 {
4634         float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4635         x1 = x * iw;
4636         x2 = (x + w) * iw;
4637         y1 = (th - y) * ih;
4638         y2 = (th - y - h) * ih;
4639         texcoord2f[0] = x1;
4640         texcoord2f[2] = x2;
4641         texcoord2f[4] = x2;
4642         texcoord2f[6] = x1;
4643         texcoord2f[1] = y1;
4644         texcoord2f[3] = y1;
4645         texcoord2f[5] = y2;
4646         texcoord2f[7] = y2;
4647 }
4648
4649 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)
4650 {
4651         int i, j, end;
4652         r_rendertarget_t *r = NULL;
4653         char vabuf[256];
4654         // first try to reuse an existing slot if possible
4655         end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
4656         for (i = 0; i < end; i++)
4657         {
4658                 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4659                 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)
4660                         break;
4661         }
4662         if (i == end)
4663         {
4664                 // no unused exact match found, so we have to make one in the first unused slot
4665                 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4666                 r->texturewidth = texturewidth;
4667                 r->textureheight = textureheight;
4668                 r->colortextype[0] = colortextype0;
4669                 r->colortextype[1] = colortextype1;
4670                 r->colortextype[2] = colortextype2;
4671                 r->colortextype[3] = colortextype3;
4672                 r->depthtextype = depthtextype;
4673                 r->depthisrenderbuffer = depthisrenderbuffer;
4674                 for (j = 0; j < 4; j++)
4675                         if (r->colortextype[j])
4676                                 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);
4677                 if (r->depthtextype)
4678                 {
4679                         if (r->depthisrenderbuffer)
4680                                 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);
4681                         else
4682                                 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);
4683                 }
4684                 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4685         }
4686         r_refdef.stats[r_stat_rendertargets_used]++;
4687         r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4688         r->lastusetime = realtime;
4689         R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4690         return r;
4691 }
4692
4693 static void R_Water_StartFrame(void)
4694 {
4695         int waterwidth, waterheight;
4696
4697         if (vid.width > (int)vid.maxtexturesize_2d || vid.height > (int)vid.maxtexturesize_2d)
4698                 return;
4699
4700         // set waterwidth and waterheight to the water resolution that will be
4701         // used (often less than the screen resolution for faster rendering)
4702         waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width);
4703         waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height);
4704         R_GetScaledViewSize(waterwidth, waterheight, &waterwidth, &waterheight);
4705
4706         if (!r_water.integer || r_showsurfaces.integer)
4707                 waterwidth = waterheight = 0;
4708
4709         // set up variables that will be used in shader setup
4710         r_fb.water.waterwidth = waterwidth;
4711         r_fb.water.waterheight = waterheight;
4712         r_fb.water.texturewidth = waterwidth;
4713         r_fb.water.textureheight = waterheight;
4714         r_fb.water.camerawidth = waterwidth;
4715         r_fb.water.cameraheight = waterheight;
4716         r_fb.water.screenscale[0] = 0.5f;
4717         r_fb.water.screenscale[1] = 0.5f;
4718         r_fb.water.screencenter[0] = 0.5f;
4719         r_fb.water.screencenter[1] = 0.5f;
4720         r_fb.water.enabled = waterwidth != 0;
4721
4722         r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4723         r_fb.water.numwaterplanes = 0;
4724 }
4725
4726 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4727 {
4728         int planeindex, bestplaneindex, vertexindex;
4729         vec3_t mins, maxs, normal, center, v, n;
4730         vec_t planescore, bestplanescore;
4731         mplane_t plane;
4732         r_waterstate_waterplane_t *p;
4733         texture_t *t = R_GetCurrentTexture(surface->texture);
4734
4735         rsurface.texture = t;
4736         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4737         // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4738         if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4739                 return;
4740         // average the vertex normals, find the surface bounds (after deformvertexes)
4741         Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4742         Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4743         VectorCopy(n, normal);
4744         VectorCopy(v, mins);
4745         VectorCopy(v, maxs);
4746         for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4747         {
4748                 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4749                 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4750                 VectorAdd(normal, n, normal);
4751                 mins[0] = min(mins[0], v[0]);
4752                 mins[1] = min(mins[1], v[1]);
4753                 mins[2] = min(mins[2], v[2]);
4754                 maxs[0] = max(maxs[0], v[0]);
4755                 maxs[1] = max(maxs[1], v[1]);
4756                 maxs[2] = max(maxs[2], v[2]);
4757         }
4758         VectorNormalize(normal);
4759         VectorMAM(0.5f, mins, 0.5f, maxs, center);
4760
4761         VectorCopy(normal, plane.normal);
4762         VectorNormalize(plane.normal);
4763         plane.dist = DotProduct(center, plane.normal);
4764         PlaneClassify(&plane);
4765         if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4766         {
4767                 // skip backfaces (except if nocullface is set)
4768 //              if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4769 //                      return;
4770                 VectorNegate(plane.normal, plane.normal);
4771                 plane.dist *= -1;
4772                 PlaneClassify(&plane);
4773         }
4774
4775
4776         // find a matching plane if there is one
4777         bestplaneindex = -1;
4778         bestplanescore = 1048576.0f;
4779         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4780         {
4781                 if(p->camera_entity == t->camera_entity)
4782                 {
4783                         planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4784                         if (bestplaneindex < 0 || bestplanescore > planescore)
4785                         {
4786                                 bestplaneindex = planeindex;
4787                                 bestplanescore = planescore;
4788                         }
4789                 }
4790         }
4791         planeindex = bestplaneindex;
4792
4793         // if this surface does not fit any known plane rendered this frame, add one
4794         if (planeindex < 0 || bestplanescore > 0.001f)
4795         {
4796                 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4797                 {
4798                         // store the new plane
4799                         planeindex = r_fb.water.numwaterplanes++;
4800                         p = r_fb.water.waterplanes + planeindex;
4801                         p->plane = plane;
4802                         // clear materialflags and pvs
4803                         p->materialflags = 0;
4804                         p->pvsvalid = false;
4805                         p->camera_entity = t->camera_entity;
4806                         VectorCopy(mins, p->mins);
4807                         VectorCopy(maxs, p->maxs);
4808                 }
4809                 else
4810                 {
4811                         // We're totally screwed.
4812                         return;
4813                 }
4814         }
4815         else
4816         {
4817                 // merge mins/maxs when we're adding this surface to the plane
4818                 p = r_fb.water.waterplanes + planeindex;
4819                 p->mins[0] = min(p->mins[0], mins[0]);
4820                 p->mins[1] = min(p->mins[1], mins[1]);
4821                 p->mins[2] = min(p->mins[2], mins[2]);
4822                 p->maxs[0] = max(p->maxs[0], maxs[0]);
4823                 p->maxs[1] = max(p->maxs[1], maxs[1]);
4824                 p->maxs[2] = max(p->maxs[2], maxs[2]);
4825         }
4826         // merge this surface's materialflags into the waterplane
4827         p->materialflags |= t->currentmaterialflags;
4828         if(!(p->materialflags & MATERIALFLAG_CAMERA))
4829         {
4830                 // merge this surface's PVS into the waterplane
4831                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4832                  && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4833                 {
4834                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4835                         p->pvsvalid = true;
4836                 }
4837         }
4838 }
4839
4840 extern cvar_t r_drawparticles;
4841 extern cvar_t r_drawdecals;
4842
4843 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4844 {
4845         int myscissor[4];
4846         r_refdef_view_t originalview;
4847         r_refdef_view_t myview;
4848         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;
4849         r_waterstate_waterplane_t *p;
4850         vec3_t visorigin;
4851         r_rendertarget_t *rt;
4852
4853         originalview = r_refdef.view;
4854
4855         // lowquality hack, temporarily shut down some cvars and restore afterwards
4856         qualityreduction = r_water_lowquality.integer;
4857         if (qualityreduction > 0)
4858         {
4859                 if (qualityreduction >= 1)
4860                 {
4861                         old_r_shadows = r_shadows.integer;
4862                         old_r_worldrtlight = r_shadow_realtime_world.integer;
4863                         old_r_dlight = r_shadow_realtime_dlight.integer;
4864                         Cvar_SetValueQuick(&r_shadows, 0);
4865                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4866                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4867                 }
4868                 if (qualityreduction >= 2)
4869                 {
4870                         old_r_dynamic = r_dynamic.integer;
4871                         old_r_particles = r_drawparticles.integer;
4872                         old_r_decals = r_drawdecals.integer;
4873                         Cvar_SetValueQuick(&r_dynamic, 0);
4874                         Cvar_SetValueQuick(&r_drawparticles, 0);
4875                         Cvar_SetValueQuick(&r_drawdecals, 0);
4876                 }
4877         }
4878
4879         for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4880         {
4881                 p->rt_reflection = NULL;
4882                 p->rt_refraction = NULL;
4883                 p->rt_camera = NULL;
4884         }
4885
4886         // render views
4887         r_refdef.view = originalview;
4888         r_refdef.view.showdebug = false;
4889         r_refdef.view.width = r_fb.water.waterwidth;
4890         r_refdef.view.height = r_fb.water.waterheight;
4891         r_refdef.view.useclipplane = true;
4892         myview = r_refdef.view;
4893         r_fb.water.renderingscene = true;
4894         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4895         {
4896                 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4897                         continue;
4898
4899                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4900                 {
4901                         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);
4902                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4903                                 goto error;
4904                         r_refdef.view = myview;
4905                         Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4906                         Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4907                         if(r_water_scissormode.integer)
4908                         {
4909                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4910                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4911                                 {
4912                                         p->rt_reflection = NULL;
4913                                         p->rt_refraction = NULL;
4914                                         p->rt_camera = NULL;
4915                                         continue;
4916                                 }
4917                         }
4918
4919                         r_refdef.view.clipplane = p->plane;
4920                         // reflected view origin may be in solid, so don't cull with it
4921                         r_refdef.view.usevieworiginculling = false;
4922                         // reverse the cullface settings for this render
4923                         r_refdef.view.cullface_front = GL_FRONT;
4924                         r_refdef.view.cullface_back = GL_BACK;
4925                         // combined pvs (based on what can be seen from each surface center)
4926                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4927                         {
4928                                 r_refdef.view.usecustompvs = true;
4929                                 if (p->pvsvalid)
4930                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4931                                 else
4932                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4933                         }
4934
4935                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4936                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4937                         GL_ScissorTest(false);
4938                         R_ClearScreen(r_refdef.fogenabled);
4939                         GL_ScissorTest(true);
4940                         if(r_water_scissormode.integer & 2)
4941                                 R_View_UpdateWithScissor(myscissor);
4942                         else
4943                                 R_View_Update();
4944                         R_AnimCache_CacheVisibleEntities();
4945                         if(r_water_scissormode.integer & 1)
4946                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4947                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4948
4949                         r_fb.water.hideplayer = false;
4950                         p->rt_reflection = rt;
4951                 }
4952
4953                 // render the normal view scene and copy into texture
4954                 // (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)
4955                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
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                         if(r_water_scissormode.integer)
4962                         {
4963                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4964                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4965                                 {
4966                                         p->rt_reflection = NULL;
4967                                         p->rt_refraction = NULL;
4968                                         p->rt_camera = NULL;
4969                                         continue;
4970                                 }
4971                         }
4972
4973                         // combined pvs (based on what can be seen from each surface center)
4974                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4975                         {
4976                                 r_refdef.view.usecustompvs = true;
4977                                 if (p->pvsvalid)
4978                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4979                                 else
4980                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4981                         }
4982
4983                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
4984
4985                         r_refdef.view.clipplane = p->plane;
4986                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
4987                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
4988
4989                         if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
4990                         {
4991                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
4992                                 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
4993                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
4994                                 R_RenderView_UpdateViewVectors();
4995                                 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
4996                                 {
4997                                         r_refdef.view.usecustompvs = true;
4998                                         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);
4999                                 }
5000                         }
5001
5002                         PlaneClassify(&r_refdef.view.clipplane);
5003
5004                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5005                         GL_ScissorTest(false);
5006                         R_ClearScreen(r_refdef.fogenabled);
5007                         GL_ScissorTest(true);
5008                         if(r_water_scissormode.integer & 2)
5009                                 R_View_UpdateWithScissor(myscissor);
5010                         else
5011                                 R_View_Update();
5012                         R_AnimCache_CacheVisibleEntities();
5013                         if(r_water_scissormode.integer & 1)
5014                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
5015                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5016
5017                         r_fb.water.hideplayer = false;
5018                         p->rt_refraction = rt;
5019                 }
5020                 else if (p->materialflags & MATERIALFLAG_CAMERA)
5021                 {
5022                         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);
5023                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5024                                 goto error;
5025                         r_refdef.view = myview;
5026
5027                         r_refdef.view.clipplane = p->plane;
5028                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5029                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5030
5031                         r_refdef.view.width = r_fb.water.camerawidth;
5032                         r_refdef.view.height = r_fb.water.cameraheight;
5033                         r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
5034                         r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
5035                         r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
5036                         r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
5037
5038                         if(p->camera_entity)
5039                         {
5040                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5041                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5042                         }
5043
5044                         // note: all of the view is used for displaying... so
5045                         // there is no use in scissoring
5046
5047                         // reverse the cullface settings for this render
5048                         r_refdef.view.cullface_front = GL_FRONT;
5049                         r_refdef.view.cullface_back = GL_BACK;
5050                         // also reverse the view matrix
5051                         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
5052                         R_RenderView_UpdateViewVectors();
5053                         if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5054                         {
5055                                 r_refdef.view.usecustompvs = true;
5056                                 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);
5057                         }
5058                         
5059                         // camera needs no clipplane
5060                         r_refdef.view.useclipplane = false;
5061                         // TODO: is the camera origin always valid?  if so we don't need to clear this
5062                         r_refdef.view.usevieworiginculling = false;
5063
5064                         PlaneClassify(&r_refdef.view.clipplane);
5065
5066                         r_fb.water.hideplayer = false;
5067
5068                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5069                         GL_ScissorTest(false);
5070                         R_ClearScreen(r_refdef.fogenabled);
5071                         GL_ScissorTest(true);
5072                         R_View_Update();
5073                         R_AnimCache_CacheVisibleEntities();
5074                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5075
5076                         r_fb.water.hideplayer = false;
5077                         p->rt_camera = rt;
5078                 }
5079
5080         }
5081         r_fb.water.renderingscene = false;
5082         r_refdef.view = originalview;
5083         R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5084         R_View_Update();
5085         R_AnimCache_CacheVisibleEntities();
5086         goto finish;
5087 error:
5088         r_refdef.view = originalview;
5089         r_fb.water.renderingscene = false;
5090         Cvar_SetValueQuick(&r_water, 0);
5091         Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed!  Turned off r_water.\n");
5092 finish:
5093         // lowquality hack, restore cvars
5094         if (qualityreduction > 0)
5095         {
5096                 if (qualityreduction >= 1)
5097                 {
5098                         Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5099                         Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5100                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5101                 }
5102                 if (qualityreduction >= 2)
5103                 {
5104                         Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5105                         Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5106                         Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5107                 }
5108         }
5109 }
5110
5111 static void R_Bloom_StartFrame(void)
5112 {
5113         int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
5114         int viewwidth, viewheight;
5115         textype_t textype = TEXTYPE_COLORBUFFER;
5116
5117         // clear the pointers to rendertargets from last frame as they're stale
5118         r_fb.rt_screen = NULL;
5119         r_fb.rt_bloom = NULL;
5120
5121         switch (vid.renderpath)
5122         {
5123         case RENDERPATH_GL20:
5124                 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5125                 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5126                 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5127                 // for simplicity, bloom requires FBO render to texture, which basically all video drivers support now
5128                 if (!vid.support.ext_framebuffer_object)
5129                         return;
5130                 break;
5131         case RENDERPATH_GLES2:
5132                 r_fb.usedepthtextures = false;
5133                 break;
5134         }
5135
5136         if (r_viewscale_fpsscaling.integer)
5137         {
5138                 double actualframetime;
5139                 double targetframetime;
5140                 double adjust;
5141                 actualframetime = r_refdef.lastdrawscreentime;
5142                 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5143                 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5144                 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5145                 if (r_viewscale_fpsscaling_stepsize.value > 0)
5146                         adjust = (int)(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5147                 viewscalefpsadjusted += adjust;
5148                 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5149         }
5150         else
5151                 viewscalefpsadjusted = 1.0f;
5152
5153         R_GetScaledViewSize(r_refdef.view.width, r_refdef.view.height, &viewwidth, &viewheight);
5154
5155         // set bloomwidth and bloomheight to the bloom resolution that will be
5156         // used (often less than the screen resolution for faster rendering)
5157         r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, vid.width);
5158         r_fb.bloomheight = r_fb.bloomwidth * vid.height / vid.width;
5159         r_fb.bloomheight = bound(1, r_fb.bloomheight, vid.height);
5160         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5161         r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5162
5163         // calculate desired texture sizes
5164         screentexturewidth = viewwidth;
5165         screentextureheight = viewheight;
5166         bloomtexturewidth = r_fb.bloomwidth;
5167         bloomtextureheight = r_fb.bloomheight;
5168
5169         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))
5170         {
5171                 Cvar_SetValueQuick(&r_bloom, 0);
5172                 Cvar_SetValueQuick(&r_motionblur, 0);
5173                 Cvar_SetValueQuick(&r_damageblur, 0);
5174         }
5175
5176         // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5177         if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5178         {
5179                 if (r_fb.ghosttexture)
5180                         R_FreeTexture(r_fb.ghosttexture);
5181                 r_fb.ghosttexture = NULL;
5182
5183                 r_fb.screentexturewidth = screentexturewidth;
5184                 r_fb.screentextureheight = screentextureheight;
5185                 r_fb.textype = textype;
5186
5187                 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5188                 {
5189                         if (r_motionblur.value > 0 || r_damageblur.value > 0)
5190                                 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);
5191                         r_fb.ghosttexture_valid = false;
5192                 }
5193         }
5194
5195         if (r_bloom.integer)
5196         {
5197                 // bloom texture is a different resolution
5198                 r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.width);
5199                 r_fb.bloomheight = r_fb.bloomwidth * r_refdef.view.height / r_refdef.view.width;
5200                 r_fb.bloomheight = bound(1, r_fb.bloomheight, r_refdef.view.height);
5201         }
5202         else
5203                 r_fb.bloomwidth = r_fb.bloomheight = 0;
5204
5205         r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5206
5207         r_refdef.view.clear = true;
5208 }
5209
5210 static void R_Bloom_MakeTexture(void)
5211 {
5212         int x, range, dir;
5213         float xoffset, yoffset, r, brighten;
5214         float colorscale = r_bloom_colorscale.value;
5215         r_viewport_t bloomviewport;
5216         r_rendertarget_t *prev, *cur;
5217         textype_t textype = r_fb.rt_screen->colortextype[0];
5218
5219         r_refdef.stats[r_stat_bloom]++;
5220
5221         R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5222
5223         // scale down screen texture to the bloom texture size
5224         CHECKGLERROR
5225         prev = r_fb.rt_screen;
5226         cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5227         R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5228         R_SetViewport(&bloomviewport);
5229         GL_CullFace(GL_NONE);
5230         GL_DepthTest(false);
5231         GL_BlendFunc(GL_ONE, GL_ZERO);
5232         GL_Color(colorscale, colorscale, colorscale, 1);
5233         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5234         // TODO: do boxfilter scale-down in shader?
5235         R_SetupShader_Generic(prev->colortexture[0], false, true, true);
5236         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5237         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5238         // we now have a properly scaled bloom image
5239
5240         // multiply bloom image by itself as many times as desired to darken it
5241         // TODO: if people actually use this it could be done more quickly in the previous shader pass
5242         for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5243         {
5244                 prev = cur;
5245                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5246                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5247                 x *= 2;
5248                 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5249                 if(x <= 2)
5250                         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0);
5251                 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5252                 GL_Color(1,1,1,1); // no fix factor supported here
5253                 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5254                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5255                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5256                 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5257         }
5258
5259         range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5260         brighten = r_bloom_brighten.value;
5261         brighten = sqrt(brighten);
5262         if(range >= 1)
5263                 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5264
5265         for (dir = 0;dir < 2;dir++)
5266         {
5267                 prev = cur;
5268                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5269                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5270                 // blend on at multiple vertical offsets to achieve a vertical blur
5271                 // TODO: do offset blends using GLSL
5272                 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5273                 GL_BlendFunc(GL_ONE, GL_ZERO);
5274                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5275                 for (x = -range;x <= range;x++)
5276                 {
5277                         if (!dir){xoffset = 0;yoffset = x;}
5278                         else {xoffset = x;yoffset = 0;}
5279                         xoffset /= (float)prev->texturewidth;
5280                         yoffset /= (float)prev->textureheight;
5281                         // compute a texcoord array with the specified x and y offset
5282                         r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5283                         r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5284                         r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5285                         r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5286                         r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5287                         r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5288                         r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5289                         r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5290                         // this r value looks like a 'dot' particle, fading sharply to
5291                         // black at the edges
5292                         // (probably not realistic but looks good enough)
5293                         //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5294                         //r = brighten/(range*2+1);
5295                         r = brighten / (range * 2 + 1);
5296                         if(range >= 1)
5297                                 r *= (1 - x*x/(float)((range+1)*(range+1)));
5298                         if (r <= 0)
5299                                 continue;
5300                         GL_Color(r, r, r, 1);
5301                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5302                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5303                         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5304                         GL_BlendFunc(GL_ONE, GL_ONE);
5305                 }
5306         }
5307
5308         // now we have the bloom image, so keep track of it
5309         r_fb.rt_bloom = cur;
5310 }
5311
5312 static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5313 {
5314         dpuint64 permutation;
5315         float uservecs[4][4];
5316         rtexture_t *viewtexture;
5317         rtexture_t *bloomtexture;
5318
5319         R_EntityMatrix(&identitymatrix);
5320
5321         if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
5322         {
5323                 // declare variables
5324                 float blur_factor, blur_mouseaccel, blur_velocity;
5325                 static float blur_average; 
5326                 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5327
5328                 // set a goal for the factoring
5329                 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value) 
5330                         / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5331                 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value) 
5332                         / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5333                 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value) 
5334                         + (blur_mouseaccel * r_motionblur_mousefactor.value));
5335
5336                 // from the goal, pick an averaged value between goal and last value
5337                 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5338                 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5339
5340                 // enforce minimum amount of blur 
5341                 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5342
5343                 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5344
5345                 // calculate values into a standard alpha
5346                 cl.motionbluralpha = 1 - exp(-
5347                                 (
5348                                         (r_motionblur.value * blur_factor / 80)
5349                                         +
5350                                         (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5351                                 )
5352                                 /
5353                                 max(0.0001, cl.time - cl.oldtime) // fps independent
5354                                 );
5355
5356                 // randomization for the blur value to combat persistent ghosting
5357                 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5358                 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5359
5360                 // apply the blur
5361                 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5362                 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5363                 {
5364                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5365                         GL_Color(1, 1, 1, cl.motionbluralpha);
5366                         R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5367                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5368                         R_SetupShader_Generic(r_fb.ghosttexture, false, true, true);
5369                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5370                         r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5371                 }
5372
5373                 // updates old view angles for next pass
5374                 VectorCopy(cl.viewangles, blur_oldangles);
5375
5376                 // copy view into the ghost texture
5377                 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5378                 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5379                 r_fb.ghosttexture_valid = true;
5380         }
5381
5382         if (r_fb.bloomwidth)
5383         {
5384                 // make the bloom texture
5385                 R_Bloom_MakeTexture();
5386         }
5387
5388 #if _MSC_VER >= 1400
5389 #define sscanf sscanf_s
5390 #endif
5391         memset(uservecs, 0, sizeof(uservecs));
5392         if (r_glsl_postprocess_uservec1_enable.integer)
5393                 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5394         if (r_glsl_postprocess_uservec2_enable.integer)
5395                 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5396         if (r_glsl_postprocess_uservec3_enable.integer)
5397                 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5398         if (r_glsl_postprocess_uservec4_enable.integer)
5399                 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5400
5401         // render to the screen fbo
5402         R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5403         GL_Color(1, 1, 1, 1);
5404         GL_BlendFunc(GL_ONE, GL_ZERO);
5405
5406         viewtexture = r_fb.rt_screen->colortexture[0];
5407         bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5408
5409         if (r_rendertarget_debug.integer >= 0)
5410         {
5411                 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5412                 if (rt && rt->colortexture[0])
5413                 {
5414                         viewtexture = rt->colortexture[0];
5415                         bloomtexture = NULL;
5416                 }
5417         }
5418
5419         R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5420         switch(vid.renderpath)
5421         {
5422         case RENDERPATH_GL20:
5423         case RENDERPATH_GLES2:
5424                 permutation =
5425                         (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5426                         | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5427                         | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5428                         | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5429                         | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5430                 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5431                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First     , viewtexture);
5432                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second    , bloomtexture);
5433                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps       );
5434                 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]);
5435                 if (r_glsl_permutation->loc_PixelSize               >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize         , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5436                 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]);
5437                 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]);
5438                 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]);
5439                 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]);
5440                 if (r_glsl_permutation->loc_Saturation              >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation        , r_glsl_saturation.value);
5441                 if (r_glsl_permutation->loc_PixelToScreenTexCoord   >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
5442                 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);
5443                 break;
5444         }
5445         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5446         r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5447 }
5448
5449 matrix4x4_t r_waterscrollmatrix;
5450
5451 void R_UpdateFog(void)
5452 {
5453         // Nehahra fog
5454         if (gamemode == GAME_NEHAHRA)
5455         {
5456                 if (gl_fogenable.integer)
5457                 {
5458                         r_refdef.oldgl_fogenable = true;
5459                         r_refdef.fog_density = gl_fogdensity.value;
5460                         r_refdef.fog_red = gl_fogred.value;
5461                         r_refdef.fog_green = gl_foggreen.value;
5462                         r_refdef.fog_blue = gl_fogblue.value;
5463                         r_refdef.fog_alpha = 1;
5464                         r_refdef.fog_start = 0;
5465                         r_refdef.fog_end = gl_skyclip.value;
5466                         r_refdef.fog_height = 1<<30;
5467                         r_refdef.fog_fadedepth = 128;
5468                 }
5469                 else if (r_refdef.oldgl_fogenable)
5470                 {
5471                         r_refdef.oldgl_fogenable = false;
5472                         r_refdef.fog_density = 0;
5473                         r_refdef.fog_red = 0;
5474                         r_refdef.fog_green = 0;
5475                         r_refdef.fog_blue = 0;
5476                         r_refdef.fog_alpha = 0;
5477                         r_refdef.fog_start = 0;
5478                         r_refdef.fog_end = 0;
5479                         r_refdef.fog_height = 1<<30;
5480                         r_refdef.fog_fadedepth = 128;
5481                 }
5482         }
5483
5484         // fog parms
5485         r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5486         r_refdef.fog_start = max(0, r_refdef.fog_start);
5487         r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5488
5489         if (r_refdef.fog_density && r_drawfog.integer)
5490         {
5491                 r_refdef.fogenabled = true;
5492                 // this is the point where the fog reaches 0.9986 alpha, which we
5493                 // consider a good enough cutoff point for the texture
5494                 // (0.9986 * 256 == 255.6)
5495                 if (r_fog_exp2.integer)
5496                         r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5497                 else
5498                         r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5499                 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5500                 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5501                 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5502                 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5503                         R_BuildFogHeightTexture();
5504                 // fog color was already set
5505                 // update the fog texture
5506                 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)
5507                         R_BuildFogTexture();
5508                 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5509                 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5510         }
5511         else
5512                 r_refdef.fogenabled = false;
5513
5514         // fog color
5515         if (r_refdef.fog_density)
5516         {
5517                 r_refdef.fogcolor[0] = r_refdef.fog_red;
5518                 r_refdef.fogcolor[1] = r_refdef.fog_green;
5519                 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5520
5521                 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5522                 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5523                 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5524                 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5525
5526                 {
5527                         vec3_t fogvec;
5528                         VectorCopy(r_refdef.fogcolor, fogvec);
5529                         //   color.rgb *= ContrastBoost * SceneBrightness;
5530                         VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5531                         r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5532                         r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5533                         r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5534                 }
5535         }
5536 }
5537
5538 void R_UpdateVariables(void)
5539 {
5540         R_Textures_Frame();
5541
5542         r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5543
5544         r_refdef.farclip = r_farclip_base.value;
5545         if (r_refdef.scene.worldmodel)
5546                 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5547         r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5548
5549         if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5550                 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5551         r_refdef.polygonfactor = 0;
5552         r_refdef.polygonoffset = 0;
5553
5554         r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5555         r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5556         r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5557         r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5558         r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5559         if (FAKELIGHT_ENABLED)
5560         {
5561                 r_refdef.scene.lightmapintensity *= r_fakelight_intensity.value;
5562         }
5563         else if (r_refdef.scene.worldmodel)
5564         {
5565                 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5566         }
5567         if (r_showsurfaces.integer)
5568         {
5569                 r_refdef.scene.rtworld = false;
5570                 r_refdef.scene.rtworldshadows = false;
5571                 r_refdef.scene.rtdlight = false;
5572                 r_refdef.scene.rtdlightshadows = false;
5573                 r_refdef.scene.lightmapintensity = 0;
5574         }
5575
5576         r_gpuskeletal = false;
5577         switch(vid.renderpath)
5578         {
5579         case RENDERPATH_GL20:
5580                 r_gpuskeletal = vid.support.arb_uniform_buffer_object && r_glsl_skeletal.integer && !r_showsurfaces.integer; // FIXME add r_showsurfaces support to GLSL skeletal!
5581         case RENDERPATH_GLES2:
5582                 if(!vid_gammatables_trivial)
5583                 {
5584                         if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5585                         {
5586                                 // build GLSL gamma texture
5587 #define RAMPWIDTH 256
5588                                 unsigned short ramp[RAMPWIDTH * 3];
5589                                 unsigned char rampbgr[RAMPWIDTH][4];
5590                                 int i;
5591
5592                                 r_texture_gammaramps_serial = vid_gammatables_serial;
5593
5594                                 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5595                                 for(i = 0; i < RAMPWIDTH; ++i)
5596                                 {
5597                                         rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5598                                         rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5599                                         rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5600                                         rampbgr[i][3] = 0;
5601                                 }
5602                                 if (r_texture_gammaramps)
5603                                 {
5604                                         R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1);
5605                                 }
5606                                 else
5607                                 {
5608                                         r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5609                                 }
5610                         }
5611                 }
5612                 else
5613                 {
5614                         // remove GLSL gamma texture
5615                 }
5616                 break;
5617         }
5618 }
5619
5620 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5621 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5622 /*
5623 ================
5624 R_SelectScene
5625 ================
5626 */
5627 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5628         if( scenetype != r_currentscenetype ) {
5629                 // store the old scenetype
5630                 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5631                 r_currentscenetype = scenetype;
5632                 // move in the new scene
5633                 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5634         }
5635 }
5636
5637 /*
5638 ================
5639 R_GetScenePointer
5640 ================
5641 */
5642 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5643 {
5644         // of course, we could also add a qboolean that provides a lock state and a ReleaseScenePointer function..
5645         if( scenetype == r_currentscenetype ) {
5646                 return &r_refdef.scene;
5647         } else {
5648                 return &r_scenes_store[ scenetype ];
5649         }
5650 }
5651
5652 static int R_SortEntities_Compare(const void *ap, const void *bp)
5653 {
5654         const entity_render_t *a = *(const entity_render_t **)ap;
5655         const entity_render_t *b = *(const entity_render_t **)bp;
5656
5657         // 1. compare model
5658         if(a->model < b->model)
5659                 return -1;
5660         if(a->model > b->model)
5661                 return +1;
5662
5663         // 2. compare skin
5664         // TODO possibly calculate the REAL skinnum here first using
5665         // skinscenes?
5666         if(a->skinnum < b->skinnum)
5667                 return -1;
5668         if(a->skinnum > b->skinnum)
5669                 return +1;
5670
5671         // everything we compared is equal
5672         return 0;
5673 }
5674 static void R_SortEntities(void)
5675 {
5676         // below or equal 2 ents, sorting never gains anything
5677         if(r_refdef.scene.numentities <= 2)
5678                 return;
5679         // sort
5680         qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5681 }
5682
5683 /*
5684 ================
5685 R_RenderView
5686 ================
5687 */
5688 extern cvar_t r_shadow_bouncegrid;
5689 extern cvar_t v_isometric;
5690 extern void V_MakeViewIsometric(void);
5691 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5692 {
5693         matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5694         int viewfbo = 0;
5695         rtexture_t *viewdepthtexture = NULL;
5696         rtexture_t *viewcolortexture = NULL;
5697         int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5698
5699         // finish any 2D rendering that was queued
5700         DrawQ_Finish();
5701
5702         if (r_timereport_active)
5703                 R_TimeReport("start");
5704         r_textureframe++; // used only by R_GetCurrentTexture
5705         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5706
5707         if(R_CompileShader_CheckStaticParms())
5708                 R_GLSL_Restart_f();
5709
5710         if (!r_drawentities.integer)
5711                 r_refdef.scene.numentities = 0;
5712         else if (r_sortentities.integer)
5713                 R_SortEntities();
5714
5715         R_AnimCache_ClearCache();
5716
5717         /* adjust for stereo display */
5718         if(R_Stereo_Active())
5719         {
5720                 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);
5721                 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5722         }
5723
5724         if (r_refdef.view.isoverlay)
5725         {
5726                 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5727                 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5728                 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5729                 R_TimeReport("depthclear");
5730
5731                 r_refdef.view.showdebug = false;
5732
5733                 r_fb.water.enabled = false;
5734                 r_fb.water.numwaterplanes = 0;
5735
5736                 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5737
5738                 r_refdef.view.matrix = originalmatrix;
5739
5740                 CHECKGLERROR
5741                 return;
5742         }
5743
5744         if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5745         {
5746                 r_refdef.view.matrix = originalmatrix;
5747                 return;
5748         }
5749
5750         r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5751         if (v_isometric.integer && r_refdef.view.ismain)
5752                 V_MakeViewIsometric();
5753
5754         r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5755
5756         if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5757                 // in sRGB fallback, behave similar to true sRGB: convert this
5758                 // value from linear to sRGB
5759                 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5760
5761         R_RenderView_UpdateViewVectors();
5762
5763         R_Shadow_UpdateWorldLightSelection();
5764
5765         // this will set up r_fb.rt_screen
5766         R_Bloom_StartFrame();
5767
5768         // apply bloom brightness offset
5769         if(r_fb.rt_bloom)
5770                 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5771
5772         // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5773         if (r_fb.rt_screen)
5774         {
5775                 viewfbo = r_fb.rt_screen->fbo;
5776                 viewdepthtexture = r_fb.rt_screen->depthtexture;
5777                 viewcolortexture = r_fb.rt_screen->colortexture[0];
5778                 viewx = 0;
5779                 viewy = 0;
5780                 viewwidth = width;
5781                 viewheight = height;
5782         }
5783
5784         R_Water_StartFrame();
5785
5786         CHECKGLERROR
5787         if (r_timereport_active)
5788                 R_TimeReport("viewsetup");
5789
5790         R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5791
5792         // clear the whole fbo every frame - otherwise the driver will consider
5793         // it to be an inter-frame texture and stall in multi-gpu configurations
5794         if (r_fb.rt_screen)
5795                 GL_ScissorTest(false);
5796         R_ClearScreen(r_refdef.fogenabled);
5797         if (r_timereport_active)
5798                 R_TimeReport("viewclear");
5799
5800         r_refdef.view.clear = true;
5801
5802         r_refdef.view.showdebug = true;
5803
5804         R_View_Update();
5805         if (r_timereport_active)
5806                 R_TimeReport("visibility");
5807
5808         R_AnimCache_CacheVisibleEntities();
5809         if (r_timereport_active)
5810                 R_TimeReport("animcache");
5811
5812         R_Shadow_UpdateBounceGridTexture();
5813         if (r_timereport_active && r_shadow_bouncegrid.integer)
5814                 R_TimeReport("bouncegrid");
5815
5816         r_fb.water.numwaterplanes = 0;
5817         if (r_fb.water.enabled)
5818                 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5819
5820         // for the actual view render we use scissoring a fair amount, so scissor
5821         // test needs to be on
5822         if (r_fb.rt_screen)
5823                 GL_ScissorTest(true);
5824         GL_Scissor(viewx, viewy, viewwidth, viewheight);
5825         R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5826         r_fb.water.numwaterplanes = 0;
5827
5828         // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5829         GL_ScissorTest(false);
5830
5831         R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
5832         if (r_timereport_active)
5833                 R_TimeReport("blendview");
5834
5835         r_refdef.view.matrix = originalmatrix;
5836
5837         CHECKGLERROR
5838
5839         // go back to 2d rendering
5840         DrawQ_Start();
5841 }
5842
5843 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5844 {
5845         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5846         {
5847                 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5848                 if (r_timereport_active)
5849                         R_TimeReport("waterworld");
5850         }
5851
5852         // don't let sound skip if going slow
5853         if (r_refdef.scene.extraupdate)
5854                 S_ExtraUpdate ();
5855
5856         R_DrawModelsAddWaterPlanes();
5857         if (r_timereport_active)
5858                 R_TimeReport("watermodels");
5859
5860         if (r_fb.water.numwaterplanes)
5861         {
5862                 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5863                 if (r_timereport_active)
5864                         R_TimeReport("waterscenes");
5865         }
5866 }
5867
5868 extern cvar_t cl_locs_show;
5869 static void R_DrawLocs(void);
5870 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5871 static void R_DrawModelDecals(void);
5872 extern cvar_t cl_decals_newsystem;
5873 extern qboolean r_shadow_usingdeferredprepass;
5874 extern int r_shadow_shadowmapatlas_modelshadows_size;
5875 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5876 {
5877         qboolean shadowmapping = false;
5878
5879         if (r_timereport_active)
5880                 R_TimeReport("beginscene");
5881
5882         r_refdef.stats[r_stat_renders]++;
5883
5884         R_UpdateFog();
5885
5886         // don't let sound skip if going slow
5887         if (r_refdef.scene.extraupdate)
5888                 S_ExtraUpdate ();
5889
5890         R_MeshQueue_BeginScene();
5891
5892         R_SkyStartFrame();
5893
5894         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);
5895
5896         if (r_timereport_active)
5897                 R_TimeReport("skystartframe");
5898
5899         if (cl.csqc_vidvars.drawworld)
5900         {
5901                 // don't let sound skip if going slow
5902                 if (r_refdef.scene.extraupdate)
5903                         S_ExtraUpdate ();
5904
5905                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5906                 {
5907                         r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5908                         if (r_timereport_active)
5909                                 R_TimeReport("worldsky");
5910                 }
5911
5912                 if (R_DrawBrushModelsSky() && r_timereport_active)
5913                         R_TimeReport("bmodelsky");
5914
5915                 if (skyrendermasked && skyrenderlater)
5916                 {
5917                         // we have to force off the water clipping plane while rendering sky
5918                         R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5919                         R_Sky();
5920                         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5921                         if (r_timereport_active)
5922                                 R_TimeReport("sky");
5923                 }
5924         }
5925
5926         // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5927         r_shadow_viewfbo = viewfbo;
5928         r_shadow_viewdepthtexture = viewdepthtexture;
5929         r_shadow_viewcolortexture = viewcolortexture;
5930         r_shadow_viewx = viewx;
5931         r_shadow_viewy = viewy;
5932         r_shadow_viewwidth = viewwidth;
5933         r_shadow_viewheight = viewheight;
5934
5935         R_Shadow_PrepareModelShadows();
5936         R_Shadow_PrepareLights();
5937         if (r_timereport_active)
5938                 R_TimeReport("preparelights");
5939
5940         // render all the shadowmaps that will be used for this view
5941         shadowmapping = R_Shadow_ShadowMappingEnabled();
5942         if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
5943         {
5944                 R_Shadow_DrawShadowMaps();
5945                 if (r_timereport_active)
5946                         R_TimeReport("shadowmaps");
5947         }
5948
5949         // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
5950         if (r_shadow_usingdeferredprepass)
5951                 R_Shadow_DrawPrepass();
5952
5953         // now we begin the forward pass of the view render
5954         if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
5955         {
5956                 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
5957                 if (r_timereport_active)
5958                         R_TimeReport("worlddepth");
5959         }
5960         if (r_depthfirst.integer >= 2)
5961         {
5962                 R_DrawModelsDepth();
5963                 if (r_timereport_active)
5964                         R_TimeReport("modeldepth");
5965         }
5966
5967         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
5968         {
5969                 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
5970                 if (r_timereport_active)
5971                         R_TimeReport("world");
5972         }
5973
5974         // don't let sound skip if going slow
5975         if (r_refdef.scene.extraupdate)
5976                 S_ExtraUpdate ();
5977
5978         R_DrawModels();
5979         if (r_timereport_active)
5980                 R_TimeReport("models");
5981
5982         // don't let sound skip if going slow
5983         if (r_refdef.scene.extraupdate)
5984                 S_ExtraUpdate ();
5985
5986         if (!r_shadow_usingdeferredprepass)
5987         {
5988                 R_Shadow_DrawLights();
5989                 if (r_timereport_active)
5990                         R_TimeReport("rtlights");
5991         }
5992
5993         // don't let sound skip if going slow
5994         if (r_refdef.scene.extraupdate)
5995                 S_ExtraUpdate ();
5996
5997         if (cl.csqc_vidvars.drawworld)
5998         {
5999                 if (cl_decals_newsystem.integer)
6000                 {
6001                         R_DrawModelDecals();
6002                         if (r_timereport_active)
6003                                 R_TimeReport("modeldecals");
6004                 }
6005                 else
6006                 {
6007                         R_DrawDecals();
6008                         if (r_timereport_active)
6009                                 R_TimeReport("decals");
6010                 }
6011
6012                 R_DrawParticles();
6013                 if (r_timereport_active)
6014                         R_TimeReport("particles");
6015
6016                 R_DrawExplosions();
6017                 if (r_timereport_active)
6018                         R_TimeReport("explosions");
6019         }
6020
6021         if (r_refdef.view.showdebug)
6022         {
6023                 if (cl_locs_show.integer)
6024                 {
6025                         R_DrawLocs();
6026                         if (r_timereport_active)
6027                                 R_TimeReport("showlocs");
6028                 }
6029
6030                 if (r_drawportals.integer)
6031                 {
6032                         R_DrawPortals();
6033                         if (r_timereport_active)
6034                                 R_TimeReport("portals");
6035                 }
6036
6037                 if (r_showbboxes_client.value > 0)
6038                 {
6039                         R_DrawEntityBBoxes(CLVM_prog);
6040                         if (r_timereport_active)
6041                                 R_TimeReport("clbboxes");
6042                 }
6043                 if (r_showbboxes.value > 0)
6044                 {
6045                         R_DrawEntityBBoxes(SVVM_prog);
6046                         if (r_timereport_active)
6047                                 R_TimeReport("svbboxes");
6048                 }
6049         }
6050
6051         if (r_transparent.integer)
6052         {
6053                 R_MeshQueue_RenderTransparent();
6054                 if (r_timereport_active)
6055                         R_TimeReport("drawtrans");
6056         }
6057
6058         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))
6059         {
6060                 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
6061                 if (r_timereport_active)
6062                         R_TimeReport("worlddebug");
6063                 R_DrawModelsDebug();
6064                 if (r_timereport_active)
6065                         R_TimeReport("modeldebug");
6066         }
6067
6068         if (cl.csqc_vidvars.drawworld)
6069         {
6070                 R_Shadow_DrawCoronas();
6071                 if (r_timereport_active)
6072                         R_TimeReport("coronas");
6073         }
6074
6075         // don't let sound skip if going slow
6076         if (r_refdef.scene.extraupdate)
6077                 S_ExtraUpdate ();
6078 }
6079
6080 static const unsigned short bboxelements[36] =
6081 {
6082         5, 1, 3, 5, 3, 7,
6083         6, 2, 0, 6, 0, 4,
6084         7, 3, 2, 7, 2, 6,
6085         4, 0, 1, 4, 1, 5,
6086         4, 5, 7, 4, 7, 6,
6087         1, 0, 2, 1, 2, 3,
6088 };
6089
6090 #define BBOXEDGES 13
6091 static const float bboxedges[BBOXEDGES][6] = 
6092 {
6093         // whole box
6094         { 0, 0, 0, 1, 1, 1 },
6095         // bottom edges
6096         { 0, 0, 0, 0, 1, 0 },
6097         { 0, 0, 0, 1, 0, 0 },
6098         { 0, 1, 0, 1, 1, 0 },
6099         { 1, 0, 0, 1, 1, 0 },
6100         // top edges
6101         { 0, 0, 1, 0, 1, 1 },
6102         { 0, 0, 1, 1, 0, 1 },
6103         { 0, 1, 1, 1, 1, 1 },
6104         { 1, 0, 1, 1, 1, 1 },
6105         // vertical edges
6106         { 0, 0, 0, 0, 0, 1 },
6107         { 1, 0, 0, 1, 0, 1 },
6108         { 0, 1, 0, 0, 1, 1 },
6109         { 1, 1, 0, 1, 1, 1 },
6110 };
6111
6112 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6113 {
6114         int numvertices = BBOXEDGES * 8;
6115         float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6116         int numtriangles = BBOXEDGES * 12;
6117         unsigned short elements[BBOXEDGES * 36];
6118         int i, edge;
6119         float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6120
6121         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6122
6123         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6124         GL_DepthMask(false);
6125         GL_DepthRange(0, 1);
6126         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6127
6128         for (edge = 0; edge < BBOXEDGES; edge++)
6129         {
6130                 for (i = 0; i < 3; i++)
6131                 {
6132                         edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6133                         edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6134                 }
6135                 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6136                 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6137                 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6138                 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6139                 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6140                 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6141                 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6142                 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6143                 for (i = 0; i < 36; i++)
6144                         elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6145         }
6146         R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6147         if (r_refdef.fogenabled)
6148         {
6149                 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6150                 {
6151                         f1 = RSurf_FogVertex(v);
6152                         f2 = 1 - f1;
6153                         c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6154                         c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6155                         c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6156                 }
6157         }
6158         R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6159         R_Mesh_ResetTextureState();
6160         R_SetupShader_Generic_NoTexture(false, false);
6161         R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6162 }
6163
6164 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6165 {
6166         // hacky overloading of the parameters
6167         prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6168         int i;
6169         float color[4];
6170         prvm_edict_t *edict;
6171
6172         GL_CullFace(GL_NONE);
6173         R_SetupShader_Generic_NoTexture(false, false);
6174
6175         for (i = 0;i < numsurfaces;i++)
6176         {
6177                 edict = PRVM_EDICT_NUM(surfacelist[i]);
6178                 switch ((int)PRVM_serveredictfloat(edict, solid))
6179                 {
6180                         case SOLID_NOT:      Vector4Set(color, 1, 1, 1, 0.05);break;
6181                         case SOLID_TRIGGER:  Vector4Set(color, 1, 0, 1, 0.10);break;
6182                         case SOLID_BBOX:     Vector4Set(color, 0, 1, 0, 0.10);break;
6183                         case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6184                         case SOLID_BSP:      Vector4Set(color, 0, 0, 1, 0.05);break;
6185                         case SOLID_CORPSE:   Vector4Set(color, 1, 0.5, 0, 0.05);break;
6186                         default:             Vector4Set(color, 0, 0, 0, 0.50);break;
6187                 }
6188                 if (prog == CLVM_prog)
6189                         color[3] *= r_showbboxes_client.value;
6190                 else
6191                         color[3] *= r_showbboxes.value;
6192                 color[3] = bound(0, color[3], 1);
6193                 GL_DepthTest(!r_showdisabledepthtest.integer);
6194                 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6195         }
6196 }
6197
6198 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6199 {
6200         int i;
6201         prvm_edict_t *edict;
6202         vec3_t center;
6203
6204         if (prog == NULL)
6205                 return;
6206
6207         for (i = 0; i < prog->num_edicts; i++)
6208         {
6209                 edict = PRVM_EDICT_NUM(i);
6210                 if (edict->priv.server->free)
6211                         continue;
6212                 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6213                 if (PRVM_serveredictedict(edict, tag_entity) != 0)
6214                         continue;
6215                 if (PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6216                         continue;
6217                 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6218                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6219         }
6220 }
6221
6222 static const int nomodelelement3i[24] =
6223 {
6224         5, 2, 0,
6225         5, 1, 2,
6226         5, 0, 3,
6227         5, 3, 1,
6228         0, 2, 4,
6229         2, 1, 4,
6230         3, 0, 4,
6231         1, 3, 4
6232 };
6233
6234 static const unsigned short nomodelelement3s[24] =
6235 {
6236         5, 2, 0,
6237         5, 1, 2,
6238         5, 0, 3,
6239         5, 3, 1,
6240         0, 2, 4,
6241         2, 1, 4,
6242         3, 0, 4,
6243         1, 3, 4
6244 };
6245
6246 static const float nomodelvertex3f[6*3] =
6247 {
6248         -16,   0,   0,
6249          16,   0,   0,
6250           0, -16,   0,
6251           0,  16,   0,
6252           0,   0, -16,
6253           0,   0,  16
6254 };
6255
6256 static const float nomodelcolor4f[6*4] =
6257 {
6258         0.0f, 0.0f, 0.5f, 1.0f,
6259         0.0f, 0.0f, 0.5f, 1.0f,
6260         0.0f, 0.5f, 0.0f, 1.0f,
6261         0.0f, 0.5f, 0.0f, 1.0f,
6262         0.5f, 0.0f, 0.0f, 1.0f,
6263         0.5f, 0.0f, 0.0f, 1.0f
6264 };
6265
6266 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6267 {
6268         int i;
6269         float f1, f2, *c;
6270         float color4f[6*4];
6271
6272         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);
6273
6274         // this is only called once per entity so numsurfaces is always 1, and
6275         // surfacelist is always {0}, so this code does not handle batches
6276
6277         if (rsurface.ent_flags & RENDER_ADDITIVE)
6278         {
6279                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6280                 GL_DepthMask(false);
6281         }
6282         else if (ent->alpha < 1)
6283         {
6284                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6285                 GL_DepthMask(false);
6286         }
6287         else
6288         {
6289                 GL_BlendFunc(GL_ONE, GL_ZERO);
6290                 GL_DepthMask(true);
6291         }
6292         GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6293         GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6294         GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6295         GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6296         memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6297         for (i = 0, c = color4f;i < 6;i++, c += 4)
6298         {
6299                 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6300                 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6301                 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6302                 c[3] *= ent->alpha;
6303         }
6304         if (r_refdef.fogenabled)
6305         {
6306                 for (i = 0, c = color4f;i < 6;i++, c += 4)
6307                 {
6308                         f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6309                         f2 = 1 - f1;
6310                         c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6311                         c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6312                         c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6313                 }
6314         }
6315 //      R_Mesh_ResetTextureState();
6316         R_SetupShader_Generic_NoTexture(false, false);
6317         R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6318         R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6319 }
6320
6321 void R_DrawNoModel(entity_render_t *ent)
6322 {
6323         vec3_t org;
6324         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6325         if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6326                 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6327         else
6328                 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6329 }
6330
6331 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6332 {
6333         vec3_t right1, right2, diff, normal;
6334
6335         VectorSubtract (org2, org1, normal);
6336
6337         // calculate 'right' vector for start
6338         VectorSubtract (r_refdef.view.origin, org1, diff);
6339         CrossProduct (normal, diff, right1);
6340         VectorNormalize (right1);
6341
6342         // calculate 'right' vector for end
6343         VectorSubtract (r_refdef.view.origin, org2, diff);
6344         CrossProduct (normal, diff, right2);
6345         VectorNormalize (right2);
6346
6347         vert[ 0] = org1[0] + width * right1[0];
6348         vert[ 1] = org1[1] + width * right1[1];
6349         vert[ 2] = org1[2] + width * right1[2];
6350         vert[ 3] = org1[0] - width * right1[0];
6351         vert[ 4] = org1[1] - width * right1[1];
6352         vert[ 5] = org1[2] - width * right1[2];
6353         vert[ 6] = org2[0] - width * right2[0];
6354         vert[ 7] = org2[1] - width * right2[1];
6355         vert[ 8] = org2[2] - width * right2[2];
6356         vert[ 9] = org2[0] + width * right2[0];
6357         vert[10] = org2[1] + width * right2[1];
6358         vert[11] = org2[2] + width * right2[2];
6359 }
6360
6361 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)
6362 {
6363         vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6364         vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6365         vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6366         vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6367         vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6368         vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6369         vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6370         vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6371         vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6372         vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6373         vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6374         vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6375 }
6376
6377 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6378 {
6379         int i;
6380         float *vertex3f;
6381         float v[3];
6382         VectorSet(v, x, y, z);
6383         for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6384                 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6385                         break;
6386         if (i == mesh->numvertices)
6387         {
6388                 if (mesh->numvertices < mesh->maxvertices)
6389                 {
6390                         VectorCopy(v, vertex3f);
6391                         mesh->numvertices++;
6392                 }
6393                 return mesh->numvertices;
6394         }
6395         else
6396                 return i;
6397 }
6398
6399 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6400 {
6401         int i;
6402         int *e, element[3];
6403         element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6404         element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6405         e = mesh->element3i + mesh->numtriangles * 3;
6406         for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6407         {
6408                 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6409                 if (mesh->numtriangles < mesh->maxtriangles)
6410                 {
6411                         *e++ = element[0];
6412                         *e++ = element[1];
6413                         *e++ = element[2];
6414                         mesh->numtriangles++;
6415                 }
6416                 element[1] = element[2];
6417         }
6418 }
6419
6420 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6421 {
6422         int i;
6423         int *e, element[3];
6424         element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6425         element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6426         e = mesh->element3i + mesh->numtriangles * 3;
6427         for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6428         {
6429                 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6430                 if (mesh->numtriangles < mesh->maxtriangles)
6431                 {
6432                         *e++ = element[0];
6433                         *e++ = element[1];
6434                         *e++ = element[2];
6435                         mesh->numtriangles++;
6436                 }
6437                 element[1] = element[2];
6438         }
6439 }
6440
6441 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6442 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6443 {
6444         int planenum, planenum2;
6445         int w;
6446         int tempnumpoints;
6447         mplane_t *plane, *plane2;
6448         double maxdist;
6449         double temppoints[2][256*3];
6450         // figure out how large a bounding box we need to properly compute this brush
6451         maxdist = 0;
6452         for (w = 0;w < numplanes;w++)
6453                 maxdist = max(maxdist, fabs(planes[w].dist));
6454         // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6455         maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6456         for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6457         {
6458                 w = 0;
6459                 tempnumpoints = 4;
6460                 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6461                 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6462                 {
6463                         if (planenum2 == planenum)
6464                                 continue;
6465                         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);
6466                         w = !w;
6467                 }
6468                 if (tempnumpoints < 3)
6469                         continue;
6470                 // generate elements forming a triangle fan for this polygon
6471                 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6472         }
6473 }
6474
6475 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)
6476 {
6477         texturelayer_t *layer;
6478         layer = t->currentlayers + t->currentnumlayers++;
6479         layer->type = type;
6480         layer->depthmask = depthmask;
6481         layer->blendfunc1 = blendfunc1;
6482         layer->blendfunc2 = blendfunc2;
6483         layer->texture = texture;
6484         layer->texmatrix = *matrix;
6485         layer->color[0] = r;
6486         layer->color[1] = g;
6487         layer->color[2] = b;
6488         layer->color[3] = a;
6489 }
6490
6491 static qboolean R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6492 {
6493         if(parms[0] == 0 && parms[1] == 0)
6494                 return false;
6495         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6496                 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6497                         return false;
6498         return true;
6499 }
6500
6501 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6502 {
6503         double index, f;
6504         index = parms[2] + rsurface.shadertime * parms[3];
6505         index -= floor(index);
6506         switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6507         {
6508         default:
6509         case Q3WAVEFUNC_NONE:
6510         case Q3WAVEFUNC_NOISE:
6511         case Q3WAVEFUNC_COUNT:
6512                 f = 0;
6513                 break;
6514         case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6515         case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6516         case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6517         case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6518         case Q3WAVEFUNC_TRIANGLE:
6519                 index *= 4;
6520                 f = index - floor(index);
6521                 if (index < 1)
6522                 {
6523                         // f = f;
6524                 }
6525                 else if (index < 2)
6526                         f = 1 - f;
6527                 else if (index < 3)
6528                         f = -f;
6529                 else
6530                         f = -(1 - f);
6531                 break;
6532         }
6533         f = parms[0] + parms[1] * f;
6534         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6535                 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6536         return (float) f;
6537 }
6538
6539 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6540 {
6541         int w, h, idx;
6542         float shadertime;
6543         float f;
6544         float offsetd[2];
6545         float tcmat[12];
6546         matrix4x4_t matrix, temp;
6547         // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6548         // it's better to have one huge fixup every 9 hours than gradual
6549         // degradation over time which looks consistently bad after many hours.
6550         //
6551         // tcmod scroll in particular suffers from this degradation which can't be
6552         // effectively worked around even with floor() tricks because we don't
6553         // know if tcmod scroll is the last tcmod being applied, and for clampmap
6554         // a workaround involving floor() would be incorrect anyway...
6555         shadertime = rsurface.shadertime;
6556         if (shadertime >= 32768.0f)
6557                 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6558         switch(tcmod->tcmod)
6559         {
6560                 case Q3TCMOD_COUNT:
6561                 case Q3TCMOD_NONE:
6562                         if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6563                                 matrix = r_waterscrollmatrix;
6564                         else
6565                                 matrix = identitymatrix;
6566                         break;
6567                 case Q3TCMOD_ENTITYTRANSLATE:
6568                         // this is used in Q3 to allow the gamecode to control texcoord
6569                         // scrolling on the entity, which is not supported in darkplaces yet.
6570                         Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6571                         break;
6572                 case Q3TCMOD_ROTATE:
6573                         Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6574                         Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6575                         Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6576                         break;
6577                 case Q3TCMOD_SCALE:
6578                         Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6579                         break;
6580                 case Q3TCMOD_SCROLL:
6581                         // this particular tcmod is a "bug for bug" compatible one with regards to
6582                         // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6583                         // specifically did the wrapping and so we must mimic that...
6584                         offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6585                         offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6586                         Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6587                         break;
6588                 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6589                         w = (int) tcmod->parms[0];
6590                         h = (int) tcmod->parms[1];
6591                         f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6592                         f = f - floor(f);
6593                         idx = (int) floor(f * w * h);
6594                         Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6595                         break;
6596                 case Q3TCMOD_STRETCH:
6597                         f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6598                         Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6599                         break;
6600                 case Q3TCMOD_TRANSFORM:
6601                         VectorSet(tcmat +  0, tcmod->parms[0], tcmod->parms[1], 0);
6602                         VectorSet(tcmat +  3, tcmod->parms[2], tcmod->parms[3], 0);
6603                         VectorSet(tcmat +  6, 0                   , 0                , 1);
6604                         VectorSet(tcmat +  9, tcmod->parms[4], tcmod->parms[5], 0);
6605                         Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6606                         break;
6607                 case Q3TCMOD_TURBULENT:
6608                         // this is handled in the RSurf_PrepareVertices function
6609                         matrix = identitymatrix;
6610                         break;
6611         }
6612         temp = *texmatrix;
6613         Matrix4x4_Concat(texmatrix, &matrix, &temp);
6614 }
6615
6616 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6617 {
6618         int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6619         char name[MAX_QPATH];
6620         skinframe_t *skinframe;
6621         unsigned char pixels[296*194];
6622         strlcpy(cache->name, skinname, sizeof(cache->name));
6623         dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6624         if (developer_loading.integer)
6625                 Con_Printf("loading %s\n", name);
6626         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6627         if (!skinframe || !skinframe->base)
6628         {
6629                 unsigned char *f;
6630                 fs_offset_t filesize;
6631                 skinframe = NULL;
6632                 f = FS_LoadFile(name, tempmempool, true, &filesize);
6633                 if (f)
6634                 {
6635                         if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6636                                 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6637                         Mem_Free(f);
6638                 }
6639         }
6640         cache->skinframe = skinframe;
6641 }
6642
6643 texture_t *R_GetCurrentTexture(texture_t *t)
6644 {
6645         int i, q;
6646         const entity_render_t *ent = rsurface.entity;
6647         dp_model_t *model = ent->model; // when calling this, ent must not be NULL
6648         q3shaderinfo_layer_tcmod_t *tcmod;
6649         float specularscale = 0.0f;
6650
6651         if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6652                 return t->currentframe;
6653         t->update_lastrenderframe = r_textureframe;
6654         t->update_lastrenderentity = (void *)ent;
6655
6656         if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6657                 t->camera_entity = ent->entitynumber;
6658         else
6659                 t->camera_entity = 0;
6660
6661         // switch to an alternate material if this is a q1bsp animated material
6662         {
6663                 texture_t *texture = t;
6664                 int s = rsurface.ent_skinnum;
6665                 if ((unsigned int)s >= (unsigned int)model->numskins)
6666                         s = 0;
6667                 if (model->skinscenes)
6668                 {
6669                         if (model->skinscenes[s].framecount > 1)
6670                                 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6671                         else
6672                                 s = model->skinscenes[s].firstframe;
6673                 }
6674                 if (s > 0)
6675                         t = t + s * model->num_surfaces;
6676                 if (t->animated)
6677                 {
6678                         // use an alternate animation if the entity's frame is not 0,
6679                         // and only if the texture has an alternate animation
6680                         if (t->animated == 2) // q2bsp
6681                                 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6682                         else if (rsurface.ent_alttextures && t->anim_total[1])
6683                                 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6684                         else
6685                                 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6686                 }
6687                 texture->currentframe = t;
6688         }
6689
6690         // update currentskinframe to be a qw skin or animation frame
6691         if (rsurface.ent_qwskin >= 0)
6692         {
6693                 i = rsurface.ent_qwskin;
6694                 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6695                 {
6696                         r_qwskincache_size = cl.maxclients;
6697                         if (r_qwskincache)
6698                                 Mem_Free(r_qwskincache);
6699                         r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6700                 }
6701                 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6702                         R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6703                 t->currentskinframe = r_qwskincache[i].skinframe;
6704                 if (t->materialshaderpass && t->currentskinframe == NULL)
6705                         t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6706         }
6707         else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6708                 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6709         if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6710                 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6711
6712         t->currentmaterialflags = t->basematerialflags;
6713         t->currentalpha = rsurface.entity->alpha * t->basealpha;
6714         if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_water.integer || r_novis.integer || r_trippy.integer))
6715                 t->currentalpha *= r_wateralpha.value;
6716         if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6717                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6718         if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6719                 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6720
6721         // decide on which type of lighting to use for this surface
6722         if (rsurface.entity->render_modellight_forced)
6723                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6724         if (rsurface.entity->render_rtlight_disabled)
6725                 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6726         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6727         {
6728                 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6729                 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT;
6730                 for (q = 0; q < 3; q++)
6731                 {
6732                         t->render_glowmod[q] = rsurface.entity->glowmod[q];
6733                         t->render_modellight_lightdir[q] = q == 2;
6734                         t->render_modellight_ambient[q] = 1;
6735                         t->render_modellight_diffuse[q] = 0;
6736                         t->render_modellight_specular[q] = 0;
6737                         t->render_lightmap_ambient[q] = 0;
6738                         t->render_lightmap_diffuse[q] = 0;
6739                         t->render_lightmap_specular[q] = 0;
6740                         t->render_rtlight_diffuse[q] = 0;
6741                         t->render_rtlight_specular[q] = 0;
6742                 }
6743         }
6744         else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6745         {
6746                 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6747                 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT;
6748                 for (q = 0; q < 3; q++)
6749                 {
6750                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6751                         t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6752                         t->render_modellight_lightdir[q] = q == 2;
6753                         t->render_modellight_diffuse[q] = 0;
6754                         t->render_modellight_specular[q] = 0;
6755                         t->render_lightmap_ambient[q] = 0;
6756                         t->render_lightmap_diffuse[q] = 0;
6757                         t->render_lightmap_specular[q] = 0;
6758                         t->render_rtlight_diffuse[q] = 0;
6759                         t->render_rtlight_specular[q] = 0;
6760                 }
6761         }
6762         else if (FAKELIGHT_ENABLED)
6763         {
6764                 // no modellight if using fakelight for the map
6765                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_NORTLIGHT) & ~(MATERIALFLAG_MODELLIGHT);
6766                 for (q = 0; q < 3; q++)
6767                 {
6768                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6769                         t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6770                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6771                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6772                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6773                         t->render_lightmap_ambient[q] = 0;
6774                         t->render_lightmap_diffuse[q] = 0;
6775                         t->render_lightmap_specular[q] = 0;
6776                         t->render_rtlight_diffuse[q] = 0;
6777                         t->render_rtlight_specular[q] = 0;
6778                 }
6779         }
6780         else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6781         {
6782                 // ambient + single direction light (modellight)
6783                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6784                 for (q = 0; q < 3; q++)
6785                 {
6786                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6787                         t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6788                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6789                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6790                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6791                         t->render_lightmap_ambient[q] = 0;
6792                         t->render_lightmap_diffuse[q] = 0;
6793                         t->render_lightmap_specular[q] = 0;
6794                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6795                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6796                 }
6797         }
6798         else
6799         {
6800                 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6801                 for (q = 0; q < 3; q++)
6802                 {
6803                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6804                         t->render_modellight_lightdir[q] = q == 2;
6805                         t->render_modellight_ambient[q] = 0;
6806                         t->render_modellight_diffuse[q] = 0;
6807                         t->render_modellight_specular[q] = 0;
6808                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6809                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6810                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6811                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6812                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6813                 }
6814         }
6815
6816         if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6817         {
6818                 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6819                 // attribute, we punt it to the lightmap path and hope for the best,
6820                 // but lighting doesn't work.
6821                 //
6822                 // FIXME: this is fine for effects but CSQC polygons should be subject
6823                 // to lighting.
6824                 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6825                 for (q = 0; q < 3; q++)
6826                 {
6827                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6828                         t->render_modellight_lightdir[q] = q == 2;
6829                         t->render_modellight_ambient[q] = 0;
6830                         t->render_modellight_diffuse[q] = 0;
6831                         t->render_modellight_specular[q] = 0;
6832                         t->render_lightmap_ambient[q] = 0;
6833                         t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6834                         t->render_lightmap_specular[q] = 0;
6835                         t->render_rtlight_diffuse[q] = 0;
6836                         t->render_rtlight_specular[q] = 0;
6837                 }
6838         }
6839
6840         for (q = 0; q < 3; q++)
6841         {
6842                 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6843                 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6844         }
6845
6846         if (rsurface.ent_flags & RENDER_ADDITIVE)
6847                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6848         else if (t->currentalpha < 1)
6849                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6850         // LordHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6851         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6852                 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6853         if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6854                 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6855         if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6856                 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6857         if (t->backgroundshaderpass)
6858                 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6859         if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6860         {
6861                 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6862                         t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6863         }
6864         else
6865                 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6866         if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6867         {
6868                 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6869                 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6870         }
6871         if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6872                 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6873
6874         // there is no tcmod
6875         if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6876         {
6877                 t->currenttexmatrix = r_waterscrollmatrix;
6878                 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6879         }
6880         else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6881         {
6882                 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6883                 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6884         }
6885
6886         if (t->materialshaderpass)
6887                 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6888                         R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6889
6890         t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6891         if (t->currentskinframe->qpixels)
6892                 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6893         t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6894         if (!t->basetexture)
6895                 t->basetexture = r_texture_notexture;
6896         t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6897         t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6898         t->nmaptexture = t->currentskinframe->nmap;
6899         if (!t->nmaptexture)
6900                 t->nmaptexture = r_texture_blanknormalmap;
6901         t->glosstexture = r_texture_black;
6902         t->glowtexture = t->currentskinframe->glow;
6903         t->fogtexture = t->currentskinframe->fog;
6904         t->reflectmasktexture = t->currentskinframe->reflect;
6905         if (t->backgroundshaderpass)
6906         {
6907                 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6908                         R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6909                 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6910                 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6911                 t->backgroundglosstexture = r_texture_black;
6912                 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6913                 if (!t->backgroundnmaptexture)
6914                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6915                 // make sure that if glow is going to be used, both textures are not NULL
6916                 if (!t->backgroundglowtexture && t->glowtexture)
6917                         t->backgroundglowtexture = r_texture_black;
6918                 if (!t->glowtexture && t->backgroundglowtexture)
6919                         t->glowtexture = r_texture_black;
6920         }
6921         else
6922         {
6923                 t->backgroundbasetexture = r_texture_white;
6924                 t->backgroundnmaptexture = r_texture_blanknormalmap;
6925                 t->backgroundglosstexture = r_texture_black;
6926                 t->backgroundglowtexture = NULL;
6927         }
6928         t->specularpower = r_shadow_glossexponent.value;
6929         // TODO: store reference values for these in the texture?
6930         if (r_shadow_gloss.integer > 0)
6931         {
6932                 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
6933                 {
6934                         if (r_shadow_glossintensity.value > 0)
6935                         {
6936                                 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
6937                                 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
6938                                 specularscale = r_shadow_glossintensity.value;
6939                         }
6940                 }
6941                 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
6942                 {
6943                         t->glosstexture = r_texture_white;
6944                         t->backgroundglosstexture = r_texture_white;
6945                         specularscale = r_shadow_gloss2intensity.value;
6946                         t->specularpower = r_shadow_gloss2exponent.value;
6947                 }
6948         }
6949         specularscale *= t->specularscalemod;
6950         t->specularpower *= t->specularpowermod;
6951
6952         // lightmaps mode looks bad with dlights using actual texturing, so turn
6953         // off the colormap and glossmap, but leave the normalmap on as it still
6954         // accurately represents the shading involved
6955         if (gl_lightmaps.integer)
6956         {
6957                 t->basetexture = r_texture_grey128;
6958                 t->pantstexture = r_texture_black;
6959                 t->shirttexture = r_texture_black;
6960                 if (gl_lightmaps.integer < 2)
6961                         t->nmaptexture = r_texture_blanknormalmap;
6962                 t->glosstexture = r_texture_black;
6963                 t->glowtexture = NULL;
6964                 t->fogtexture = NULL;
6965                 t->reflectmasktexture = NULL;
6966                 t->backgroundbasetexture = NULL;
6967                 if (gl_lightmaps.integer < 2)
6968                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6969                 t->backgroundglosstexture = r_texture_black;
6970                 t->backgroundglowtexture = NULL;
6971                 specularscale = 0;
6972                 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
6973         }
6974
6975         if (specularscale != 1.0f)
6976         {
6977                 for (q = 0; q < 3; q++)
6978                 {
6979                         t->render_modellight_specular[q] *= specularscale;
6980                         t->render_lightmap_specular[q] *= specularscale;
6981                         t->render_rtlight_specular[q] *= specularscale;
6982                 }
6983         }
6984
6985         t->currentnumlayers = 0;
6986         if (t->currentmaterialflags & MATERIALFLAG_WALL)
6987         {
6988                 int blendfunc1, blendfunc2;
6989                 qboolean depthmask;
6990                 if (t->currentmaterialflags & MATERIALFLAG_ADD)
6991                 {
6992                         blendfunc1 = GL_SRC_ALPHA;
6993                         blendfunc2 = GL_ONE;
6994                 }
6995                 else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
6996                 {
6997                         blendfunc1 = GL_SRC_ALPHA;
6998                         blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
6999                 }
7000                 else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
7001                 {
7002                         blendfunc1 = t->customblendfunc[0];
7003                         blendfunc2 = t->customblendfunc[1];
7004                 }
7005                 else
7006                 {
7007                         blendfunc1 = GL_ONE;
7008                         blendfunc2 = GL_ZERO;
7009                 }
7010                 depthmask = !(t->currentmaterialflags & MATERIALFLAG_BLENDED);
7011                 if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
7012                 {
7013                         // basic lit geometry
7014                         R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE, t->basetexture, &t->currenttexmatrix, 2, 2, 2, t->currentalpha);
7015                         // add pants/shirt if needed
7016                         if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7017                                 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);
7018                         if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7019                                 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);
7020                 }
7021                 else
7022                 {
7023                         // basic lit geometry
7024                         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);
7025                         // add pants/shirt if needed
7026                         if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7027                                 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);
7028                         if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7029                                 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);
7030                         // now add ambient passes if needed
7031                         if (VectorLength2(t->render_lightmap_ambient) >= (1.0f/1048576.0f))
7032                         {
7033                                 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);
7034                                 if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7035                                         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);
7036                                 if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7037                                         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);
7038                         }
7039                 }
7040                 if (t->glowtexture != NULL && !gl_lightmaps.integer)
7041                         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);
7042                 if (r_refdef.fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD))
7043                 {
7044                         // if this is opaque use alpha blend which will darken the earlier
7045                         // passes cheaply.
7046                         //
7047                         // if this is an alpha blended material, all the earlier passes
7048                         // were darkened by fog already, so we only need to add the fog
7049                         // color ontop through the fog mask texture
7050                         //
7051                         // if this is an additive blended material, all the earlier passes
7052                         // were darkened by fog already, and we should not add fog color
7053                         // (because the background was not darkened, there is no fog color
7054                         // that was lost behind it).
7055                         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);
7056                 }
7057         }
7058
7059         return t;
7060 }
7061
7062 rsurfacestate_t rsurface;
7063
7064 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
7065 {
7066         dp_model_t *model = ent->model;
7067         //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
7068         //      return;
7069         rsurface.entity = (entity_render_t *)ent;
7070         rsurface.skeleton = ent->skeleton;
7071         memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
7072         rsurface.ent_skinnum = ent->skinnum;
7073         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;
7074         rsurface.ent_flags = ent->flags;
7075         if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
7076                 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
7077         rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
7078         rsurface.matrix = ent->matrix;
7079         rsurface.inversematrix = ent->inversematrix;
7080         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7081         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7082         R_EntityMatrix(&rsurface.matrix);
7083         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7084         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7085         rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
7086         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7087         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7088         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7089         memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
7090         rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
7091         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7092         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7093         if (ent->model->brush.submodel && !prepass)
7094         {
7095                 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
7096                 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
7097         }
7098         // if the animcache code decided it should use the shader path, skip the deform step
7099         rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
7100         rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
7101         rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
7102         rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
7103         rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
7104         if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
7105         {
7106                 if (ent->animcache_vertex3f)
7107                 {
7108                         r_refdef.stats[r_stat_batch_entitycache_count]++;
7109                         r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
7110                         r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
7111                         r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
7112                         rsurface.modelvertex3f = ent->animcache_vertex3f;
7113                         rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
7114                         rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
7115                         rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
7116                         rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
7117                         rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
7118                         rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
7119                         rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
7120                         rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
7121                         rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
7122                         rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
7123                         rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
7124                 }
7125                 else if (wanttangents)
7126                 {
7127                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7128                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7129                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7130                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7131                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7132                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7133                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7134                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7135                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
7136                         rsurface.modelvertex3f_vertexbuffer = NULL;
7137                         rsurface.modelvertex3f_bufferoffset = 0;
7138                         rsurface.modelvertex3f_vertexbuffer = 0;
7139                         rsurface.modelvertex3f_bufferoffset = 0;
7140                         rsurface.modelsvector3f_vertexbuffer = 0;
7141                         rsurface.modelsvector3f_bufferoffset = 0;
7142                         rsurface.modeltvector3f_vertexbuffer = 0;
7143                         rsurface.modeltvector3f_bufferoffset = 0;
7144                         rsurface.modelnormal3f_vertexbuffer = 0;
7145                         rsurface.modelnormal3f_bufferoffset = 0;
7146                 }
7147                 else if (wantnormals)
7148                 {
7149                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7150                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7151                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7152                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7153                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7154                         rsurface.modelsvector3f = NULL;
7155                         rsurface.modeltvector3f = NULL;
7156                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7157                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
7158                         rsurface.modelvertex3f_vertexbuffer = NULL;
7159                         rsurface.modelvertex3f_bufferoffset = 0;
7160                         rsurface.modelvertex3f_vertexbuffer = 0;
7161                         rsurface.modelvertex3f_bufferoffset = 0;
7162                         rsurface.modelsvector3f_vertexbuffer = 0;
7163                         rsurface.modelsvector3f_bufferoffset = 0;
7164                         rsurface.modeltvector3f_vertexbuffer = 0;
7165                         rsurface.modeltvector3f_bufferoffset = 0;
7166                         rsurface.modelnormal3f_vertexbuffer = 0;
7167                         rsurface.modelnormal3f_bufferoffset = 0;
7168                 }
7169                 else
7170                 {
7171                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7172                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7173                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7174                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7175                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7176                         rsurface.modelsvector3f = NULL;
7177                         rsurface.modeltvector3f = NULL;
7178                         rsurface.modelnormal3f = NULL;
7179                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7180                         rsurface.modelvertex3f_vertexbuffer = NULL;
7181                         rsurface.modelvertex3f_bufferoffset = 0;
7182                         rsurface.modelvertex3f_vertexbuffer = 0;
7183                         rsurface.modelvertex3f_bufferoffset = 0;
7184                         rsurface.modelsvector3f_vertexbuffer = 0;
7185                         rsurface.modelsvector3f_bufferoffset = 0;
7186                         rsurface.modeltvector3f_vertexbuffer = 0;
7187                         rsurface.modeltvector3f_bufferoffset = 0;
7188                         rsurface.modelnormal3f_vertexbuffer = 0;
7189                         rsurface.modelnormal3f_bufferoffset = 0;
7190                 }
7191                 rsurface.modelgeneratedvertex = true;
7192         }
7193         else
7194         {
7195                 if (rsurface.entityskeletaltransform3x4)
7196                 {
7197                         r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7198                         r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7199                         r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7200                         r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7201                 }
7202                 else
7203                 {
7204                         r_refdef.stats[r_stat_batch_entitystatic_count]++;
7205                         r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7206                         r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7207                         r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7208                 }
7209                 rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
7210                 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7211                 rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
7212                 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7213                 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7214                 rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f;
7215                 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7216                 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7217                 rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f;
7218                 rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
7219                 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7220                 rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f;
7221                 rsurface.modelgeneratedvertex = false;
7222         }
7223         rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
7224         rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7225         rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f;
7226         rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
7227         rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7228         rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f;
7229         rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
7230         rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7231         rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
7232         rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7233         rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7234         rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.vbooffset_skeletalindex4ub;
7235         rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7236         rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7237         rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.vbooffset_skeletalweight4ub;
7238         rsurface.modelelement3i = model->surfmesh.data_element3i;
7239         rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7240         rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7241         rsurface.modelelement3s = model->surfmesh.data_element3s;
7242         rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7243         rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7244         rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7245         rsurface.modelnumvertices = model->surfmesh.num_vertices;
7246         rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7247         rsurface.modelsurfaces = model->data_surfaces;
7248         rsurface.batchgeneratedvertex = false;
7249         rsurface.batchfirstvertex = 0;
7250         rsurface.batchnumvertices = 0;
7251         rsurface.batchfirsttriangle = 0;
7252         rsurface.batchnumtriangles = 0;
7253         rsurface.batchvertex3f  = NULL;
7254         rsurface.batchvertex3f_vertexbuffer = NULL;
7255         rsurface.batchvertex3f_bufferoffset = 0;
7256         rsurface.batchsvector3f = NULL;
7257         rsurface.batchsvector3f_vertexbuffer = NULL;
7258         rsurface.batchsvector3f_bufferoffset = 0;
7259         rsurface.batchtvector3f = NULL;
7260         rsurface.batchtvector3f_vertexbuffer = NULL;
7261         rsurface.batchtvector3f_bufferoffset = 0;
7262         rsurface.batchnormal3f  = NULL;
7263         rsurface.batchnormal3f_vertexbuffer = NULL;
7264         rsurface.batchnormal3f_bufferoffset = 0;
7265         rsurface.batchlightmapcolor4f = NULL;
7266         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7267         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7268         rsurface.batchtexcoordtexture2f = NULL;
7269         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7270         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7271         rsurface.batchtexcoordlightmap2f = NULL;
7272         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7273         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7274         rsurface.batchskeletalindex4ub = NULL;
7275         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7276         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7277         rsurface.batchskeletalweight4ub = NULL;
7278         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7279         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7280         rsurface.batchelement3i = NULL;
7281         rsurface.batchelement3i_indexbuffer = NULL;
7282         rsurface.batchelement3i_bufferoffset = 0;
7283         rsurface.batchelement3s = NULL;
7284         rsurface.batchelement3s_indexbuffer = NULL;
7285         rsurface.batchelement3s_bufferoffset = 0;
7286         rsurface.forcecurrenttextureupdate = false;
7287 }
7288
7289 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)
7290 {
7291         rsurface.entity = r_refdef.scene.worldentity;
7292         rsurface.skeleton = NULL;
7293         rsurface.ent_skinnum = 0;
7294         rsurface.ent_qwskin = -1;
7295         rsurface.ent_flags = entflags;
7296         rsurface.shadertime = r_refdef.scene.time - shadertime;
7297         rsurface.modelnumvertices = numvertices;
7298         rsurface.modelnumtriangles = numtriangles;
7299         rsurface.matrix = *matrix;
7300         rsurface.inversematrix = *inversematrix;
7301         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7302         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7303         R_EntityMatrix(&rsurface.matrix);
7304         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7305         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7306         rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7307         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7308         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7309         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7310         memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7311         rsurface.frameblend[0].lerp = 1;
7312         rsurface.ent_alttextures = false;
7313         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7314         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7315         rsurface.entityskeletaltransform3x4 = NULL;
7316         rsurface.entityskeletaltransform3x4buffer = NULL;
7317         rsurface.entityskeletaltransform3x4offset = 0;
7318         rsurface.entityskeletaltransform3x4size = 0;
7319         rsurface.entityskeletalnumtransforms = 0;
7320         r_refdef.stats[r_stat_batch_entitycustom_count]++;
7321         r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7322         r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7323         r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7324         if (wanttangents)
7325         {
7326                 rsurface.modelvertex3f = (float *)vertex3f;
7327                 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7328                 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7329                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7330         }
7331         else if (wantnormals)
7332         {
7333                 rsurface.modelvertex3f = (float *)vertex3f;
7334                 rsurface.modelsvector3f = NULL;
7335                 rsurface.modeltvector3f = NULL;
7336                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7337         }
7338         else
7339         {
7340                 rsurface.modelvertex3f = (float *)vertex3f;
7341                 rsurface.modelsvector3f = NULL;
7342                 rsurface.modeltvector3f = NULL;
7343                 rsurface.modelnormal3f = NULL;
7344         }
7345         rsurface.modelvertex3f_vertexbuffer = 0;
7346         rsurface.modelvertex3f_bufferoffset = 0;
7347         rsurface.modelsvector3f_vertexbuffer = 0;
7348         rsurface.modelsvector3f_bufferoffset = 0;
7349         rsurface.modeltvector3f_vertexbuffer = 0;
7350         rsurface.modeltvector3f_bufferoffset = 0;
7351         rsurface.modelnormal3f_vertexbuffer = 0;
7352         rsurface.modelnormal3f_bufferoffset = 0;
7353         rsurface.modelgeneratedvertex = true;
7354         rsurface.modellightmapcolor4f  = (float *)color4f;
7355         rsurface.modellightmapcolor4f_vertexbuffer = 0;
7356         rsurface.modellightmapcolor4f_bufferoffset = 0;
7357         rsurface.modeltexcoordtexture2f  = (float *)texcoord2f;
7358         rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7359         rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7360         rsurface.modeltexcoordlightmap2f  = NULL;
7361         rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7362         rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7363         rsurface.modelskeletalindex4ub = NULL;
7364         rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7365         rsurface.modelskeletalindex4ub_bufferoffset = 0;
7366         rsurface.modelskeletalweight4ub = NULL;
7367         rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7368         rsurface.modelskeletalweight4ub_bufferoffset = 0;
7369         rsurface.modelelement3i = (int *)element3i;
7370         rsurface.modelelement3i_indexbuffer = NULL;
7371         rsurface.modelelement3i_bufferoffset = 0;
7372         rsurface.modelelement3s = (unsigned short *)element3s;
7373         rsurface.modelelement3s_indexbuffer = NULL;
7374         rsurface.modelelement3s_bufferoffset = 0;
7375         rsurface.modellightmapoffsets = NULL;
7376         rsurface.modelsurfaces = NULL;
7377         rsurface.batchgeneratedvertex = false;
7378         rsurface.batchfirstvertex = 0;
7379         rsurface.batchnumvertices = 0;
7380         rsurface.batchfirsttriangle = 0;
7381         rsurface.batchnumtriangles = 0;
7382         rsurface.batchvertex3f  = NULL;
7383         rsurface.batchvertex3f_vertexbuffer = NULL;
7384         rsurface.batchvertex3f_bufferoffset = 0;
7385         rsurface.batchsvector3f = NULL;
7386         rsurface.batchsvector3f_vertexbuffer = NULL;
7387         rsurface.batchsvector3f_bufferoffset = 0;
7388         rsurface.batchtvector3f = NULL;
7389         rsurface.batchtvector3f_vertexbuffer = NULL;
7390         rsurface.batchtvector3f_bufferoffset = 0;
7391         rsurface.batchnormal3f  = NULL;
7392         rsurface.batchnormal3f_vertexbuffer = NULL;
7393         rsurface.batchnormal3f_bufferoffset = 0;
7394         rsurface.batchlightmapcolor4f = NULL;
7395         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7396         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7397         rsurface.batchtexcoordtexture2f = NULL;
7398         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7399         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7400         rsurface.batchtexcoordlightmap2f = NULL;
7401         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7402         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7403         rsurface.batchskeletalindex4ub = NULL;
7404         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7405         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7406         rsurface.batchskeletalweight4ub = NULL;
7407         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7408         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7409         rsurface.batchelement3i = NULL;
7410         rsurface.batchelement3i_indexbuffer = NULL;
7411         rsurface.batchelement3i_bufferoffset = 0;
7412         rsurface.batchelement3s = NULL;
7413         rsurface.batchelement3s_indexbuffer = NULL;
7414         rsurface.batchelement3s_bufferoffset = 0;
7415         rsurface.forcecurrenttextureupdate = true;
7416
7417         if (rsurface.modelnumvertices && rsurface.modelelement3i)
7418         {
7419                 if ((wantnormals || wanttangents) && !normal3f)
7420                 {
7421                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7422                         Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7423                 }
7424                 if (wanttangents && !svector3f)
7425                 {
7426                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7427                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7428                         Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7429                 }
7430         }
7431 }
7432
7433 float RSurf_FogPoint(const float *v)
7434 {
7435         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7436         float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7437         float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7438         float FogHeightFade = r_refdef.fogheightfade;
7439         float fogfrac;
7440         unsigned int fogmasktableindex;
7441         if (r_refdef.fogplaneviewabove)
7442                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7443         else
7444                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7445         fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7446         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7447 }
7448
7449 float RSurf_FogVertex(const float *v)
7450 {
7451         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7452         float FogPlaneViewDist = rsurface.fogplaneviewdist;
7453         float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7454         float FogHeightFade = rsurface.fogheightfade;
7455         float fogfrac;
7456         unsigned int fogmasktableindex;
7457         if (r_refdef.fogplaneviewabove)
7458                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7459         else
7460                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7461         fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7462         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7463 }
7464
7465 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7466 {
7467         int i;
7468         for (i = 0;i < numelements;i++)
7469                 outelement3i[i] = inelement3i[i] + adjust;
7470 }
7471
7472 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7473 extern cvar_t gl_vbo;
7474 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7475 {
7476         int deformindex;
7477         int firsttriangle;
7478         int numtriangles;
7479         int firstvertex;
7480         int endvertex;
7481         int numvertices;
7482         int surfacefirsttriangle;
7483         int surfacenumtriangles;
7484         int surfacefirstvertex;
7485         int surfaceendvertex;
7486         int surfacenumvertices;
7487         int batchnumsurfaces = texturenumsurfaces;
7488         int batchnumvertices;
7489         int batchnumtriangles;
7490         int i, j;
7491         qboolean gaps;
7492         qboolean dynamicvertex;
7493         float amplitude;
7494         float animpos;
7495         float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7496         float waveparms[4];
7497         unsigned char *ub;
7498         q3shaderinfo_deform_t *deform;
7499         const msurface_t *surface, *firstsurface;
7500         if (!texturenumsurfaces)
7501                 return;
7502         // find vertex range of this surface batch
7503         gaps = false;
7504         firstsurface = texturesurfacelist[0];
7505         firsttriangle = firstsurface->num_firsttriangle;
7506         batchnumvertices = 0;
7507         batchnumtriangles = 0;
7508         firstvertex = endvertex = firstsurface->num_firstvertex;
7509         for (i = 0;i < texturenumsurfaces;i++)
7510         {
7511                 surface = texturesurfacelist[i];
7512                 if (surface != firstsurface + i)
7513                         gaps = true;
7514                 surfacefirstvertex = surface->num_firstvertex;
7515                 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7516                 surfacenumvertices = surface->num_vertices;
7517                 surfacenumtriangles = surface->num_triangles;
7518                 if (firstvertex > surfacefirstvertex)
7519                         firstvertex = surfacefirstvertex;
7520                 if (endvertex < surfaceendvertex)
7521                         endvertex = surfaceendvertex;
7522                 batchnumvertices += surfacenumvertices;
7523                 batchnumtriangles += surfacenumtriangles;
7524         }
7525
7526         r_refdef.stats[r_stat_batch_batches]++;
7527         if (gaps)
7528                 r_refdef.stats[r_stat_batch_withgaps]++;
7529         r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7530         r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7531         r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7532
7533         // we now know the vertex range used, and if there are any gaps in it
7534         rsurface.batchfirstvertex = firstvertex;
7535         rsurface.batchnumvertices = endvertex - firstvertex;
7536         rsurface.batchfirsttriangle = firsttriangle;
7537         rsurface.batchnumtriangles = batchnumtriangles;
7538
7539         // check if any dynamic vertex processing must occur
7540         dynamicvertex = false;
7541
7542         // a cvar to force the dynamic vertex path to be taken, for debugging
7543         if (r_batch_debugdynamicvertexpath.integer)
7544         {
7545                 if (!dynamicvertex)
7546                 {
7547                         r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7548                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7549                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7550                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7551                 }
7552                 dynamicvertex = true;
7553         }
7554
7555         // if there is a chance of animated vertex colors, it's a dynamic batch
7556         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
7557         {
7558                 if (!dynamicvertex)
7559                 {
7560                         r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7561                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7562                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7563                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7564                 }
7565                 dynamicvertex = true;
7566         }
7567
7568         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7569         {
7570                 switch (deform->deform)
7571                 {
7572                 default:
7573                 case Q3DEFORM_PROJECTIONSHADOW:
7574                 case Q3DEFORM_TEXT0:
7575                 case Q3DEFORM_TEXT1:
7576                 case Q3DEFORM_TEXT2:
7577                 case Q3DEFORM_TEXT3:
7578                 case Q3DEFORM_TEXT4:
7579                 case Q3DEFORM_TEXT5:
7580                 case Q3DEFORM_TEXT6:
7581                 case Q3DEFORM_TEXT7:
7582                 case Q3DEFORM_NONE:
7583                         break;
7584                 case Q3DEFORM_AUTOSPRITE:
7585                         if (!dynamicvertex)
7586                         {
7587                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7588                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7589                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7590                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7591                         }
7592                         dynamicvertex = true;
7593                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7594                         break;
7595                 case Q3DEFORM_AUTOSPRITE2:
7596                         if (!dynamicvertex)
7597                         {
7598                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7599                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7600                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7601                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7602                         }
7603                         dynamicvertex = true;
7604                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7605                         break;
7606                 case Q3DEFORM_NORMAL:
7607                         if (!dynamicvertex)
7608                         {
7609                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7610                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7611                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7612                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7613                         }
7614                         dynamicvertex = true;
7615                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7616                         break;
7617                 case Q3DEFORM_WAVE:
7618                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7619                                 break; // if wavefunc is a nop, ignore this transform
7620                         if (!dynamicvertex)
7621                         {
7622                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7623                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7624                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7625                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7626                         }
7627                         dynamicvertex = true;
7628                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7629                         break;
7630                 case Q3DEFORM_BULGE:
7631                         if (!dynamicvertex)
7632                         {
7633                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7634                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7635                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7636                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7637                         }
7638                         dynamicvertex = true;
7639                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7640                         break;
7641                 case Q3DEFORM_MOVE:
7642                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7643                                 break; // if wavefunc is a nop, ignore this transform
7644                         if (!dynamicvertex)
7645                         {
7646                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7647                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7648                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7649                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7650                         }
7651                         dynamicvertex = true;
7652                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7653                         break;
7654                 }
7655         }
7656         if (rsurface.texture->materialshaderpass)
7657         {
7658                 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7659                 {
7660                 default:
7661                 case Q3TCGEN_TEXTURE:
7662                         break;
7663                 case Q3TCGEN_LIGHTMAP:
7664                         if (!dynamicvertex)
7665                         {
7666                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7667                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7668                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7669                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7670                         }
7671                         dynamicvertex = true;
7672                         batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7673                         break;
7674                 case Q3TCGEN_VECTOR:
7675                         if (!dynamicvertex)
7676                         {
7677                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7678                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7679                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7680                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7681                         }
7682                         dynamicvertex = true;
7683                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7684                         break;
7685                 case Q3TCGEN_ENVIRONMENT:
7686                         if (!dynamicvertex)
7687                         {
7688                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7689                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7690                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7691                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7692                         }
7693                         dynamicvertex = true;
7694                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7695                         break;
7696                 }
7697                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7698                 {
7699                         if (!dynamicvertex)
7700                         {
7701                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7702                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7703                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7704                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7705                         }
7706                         dynamicvertex = true;
7707                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7708                 }
7709         }
7710
7711         // the caller can specify BATCHNEED_NOGAPS to force a batch with
7712         // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7713         // we ensure this by treating the vertex batch as dynamic...
7714         if ((batchneed & BATCHNEED_ALWAYSCOPY) || ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0)))
7715         {
7716                 if (!dynamicvertex)
7717                 {
7718                         r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7719                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7720                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7721                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7722                 }
7723                 dynamicvertex = true;
7724         }
7725
7726         // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7727         if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7728                 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7729
7730         rsurface.batchvertex3f = rsurface.modelvertex3f;
7731         rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7732         rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7733         rsurface.batchsvector3f = rsurface.modelsvector3f;
7734         rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7735         rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7736         rsurface.batchtvector3f = rsurface.modeltvector3f;
7737         rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7738         rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7739         rsurface.batchnormal3f = rsurface.modelnormal3f;
7740         rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7741         rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7742         rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7743         rsurface.batchlightmapcolor4f_vertexbuffer  = rsurface.modellightmapcolor4f_vertexbuffer;
7744         rsurface.batchlightmapcolor4f_bufferoffset  = rsurface.modellightmapcolor4f_bufferoffset;
7745         rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7746         rsurface.batchtexcoordtexture2f_vertexbuffer  = rsurface.modeltexcoordtexture2f_vertexbuffer;
7747         rsurface.batchtexcoordtexture2f_bufferoffset  = rsurface.modeltexcoordtexture2f_bufferoffset;
7748         rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7749         rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7750         rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7751         rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7752         rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7753         rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7754         rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7755         rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7756         rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7757         rsurface.batchelement3i = rsurface.modelelement3i;
7758         rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7759         rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7760         rsurface.batchelement3s = rsurface.modelelement3s;
7761         rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7762         rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7763         rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7764         rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7765         rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7766         rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7767         rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7768
7769         // if any dynamic vertex processing has to occur in software, we copy the
7770         // entire surface list together before processing to rebase the vertices
7771         // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7772         //
7773         // if any gaps exist and we do not have a static vertex buffer, we have to
7774         // copy the surface list together to avoid wasting upload bandwidth on the
7775         // vertices in the gaps.
7776         //
7777         // if gaps exist and we have a static vertex buffer, we can choose whether
7778         // to combine the index buffer ranges into one dynamic index buffer or
7779         // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7780         //
7781         // in many cases the batch is reduced to one draw call.
7782
7783         rsurface.batchmultidraw = false;
7784         rsurface.batchmultidrawnumsurfaces = 0;
7785         rsurface.batchmultidrawsurfacelist = NULL;
7786
7787         if (!dynamicvertex)
7788         {
7789                 // static vertex data, just set pointers...
7790                 rsurface.batchgeneratedvertex = false;
7791                 // if there are gaps, we want to build a combined index buffer,
7792                 // otherwise use the original static buffer with an appropriate offset
7793                 if (gaps)
7794                 {
7795                         r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7796                         r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7797                         r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7798                         r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7799                         if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7800                         {
7801                                 rsurface.batchmultidraw = true;
7802                                 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7803                                 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7804                                 return;
7805                         }
7806                         // build a new triangle elements array for this batch
7807                         rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7808                         rsurface.batchfirsttriangle = 0;
7809                         numtriangles = 0;
7810                         for (i = 0;i < texturenumsurfaces;i++)
7811                         {
7812                                 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7813                                 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7814                                 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7815                                 numtriangles += surfacenumtriangles;
7816                         }
7817                         rsurface.batchelement3i_indexbuffer = NULL;
7818                         rsurface.batchelement3i_bufferoffset = 0;
7819                         rsurface.batchelement3s = NULL;
7820                         rsurface.batchelement3s_indexbuffer = NULL;
7821                         rsurface.batchelement3s_bufferoffset = 0;
7822                         if (endvertex <= 65536)
7823                         {
7824                                 // make a 16bit (unsigned short) index array if possible
7825                                 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7826                                 for (i = 0;i < numtriangles*3;i++)
7827                                         rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7828                         }
7829                         // upload buffer data for the copytriangles batch
7830                         if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo)
7831                         {
7832                                 if (rsurface.batchelement3s)
7833                                         rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
7834                                 else if (rsurface.batchelement3i)
7835                                         rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
7836                         }
7837                 }
7838                 else
7839                 {
7840                         r_refdef.stats[r_stat_batch_fast_batches] += 1;
7841                         r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
7842                         r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
7843                         r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
7844                 }
7845                 return;
7846         }
7847
7848         // something needs software processing, do it for real...
7849         // we only directly handle separate array data in this case and then
7850         // generate interleaved data if needed...
7851         rsurface.batchgeneratedvertex = true;
7852         r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
7853         r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
7854         r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
7855         r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
7856
7857         // now copy the vertex data into a combined array and make an index array
7858         // (this is what Quake3 does all the time)
7859         // we also apply any skeletal animation here that would have been done in
7860         // the vertex shader, because most of the dynamic vertex animation cases
7861         // need actual vertex positions and normals
7862         //if (dynamicvertex)
7863         {
7864                 rsurface.batchvertex3f = NULL;
7865                 rsurface.batchvertex3f_vertexbuffer = NULL;
7866                 rsurface.batchvertex3f_bufferoffset = 0;
7867                 rsurface.batchsvector3f = NULL;
7868                 rsurface.batchsvector3f_vertexbuffer = NULL;
7869                 rsurface.batchsvector3f_bufferoffset = 0;
7870                 rsurface.batchtvector3f = NULL;
7871                 rsurface.batchtvector3f_vertexbuffer = NULL;
7872                 rsurface.batchtvector3f_bufferoffset = 0;
7873                 rsurface.batchnormal3f = NULL;
7874                 rsurface.batchnormal3f_vertexbuffer = NULL;
7875                 rsurface.batchnormal3f_bufferoffset = 0;
7876                 rsurface.batchlightmapcolor4f = NULL;
7877                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7878                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7879                 rsurface.batchtexcoordtexture2f = NULL;
7880                 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7881                 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7882                 rsurface.batchtexcoordlightmap2f = NULL;
7883                 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7884                 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7885                 rsurface.batchskeletalindex4ub = NULL;
7886                 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7887                 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7888                 rsurface.batchskeletalweight4ub = NULL;
7889                 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7890                 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7891                 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7892                 rsurface.batchelement3i_indexbuffer = NULL;
7893                 rsurface.batchelement3i_bufferoffset = 0;
7894                 rsurface.batchelement3s = NULL;
7895                 rsurface.batchelement3s_indexbuffer = NULL;
7896                 rsurface.batchelement3s_bufferoffset = 0;
7897                 rsurface.batchskeletaltransform3x4buffer = NULL;
7898                 rsurface.batchskeletaltransform3x4offset = 0;
7899                 rsurface.batchskeletaltransform3x4size = 0;
7900                 // we'll only be setting up certain arrays as needed
7901                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7902                         rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7903                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7904                         rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7905                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7906                 {
7907                         rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7908                         rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7909                 }
7910                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7911                         rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
7912                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7913                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7914                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7915                         rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7916                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7917                 {
7918                         rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7919                         rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7920                 }
7921                 numvertices = 0;
7922                 numtriangles = 0;
7923                 for (i = 0;i < texturenumsurfaces;i++)
7924                 {
7925                         surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
7926                         surfacenumvertices = texturesurfacelist[i]->num_vertices;
7927                         surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7928                         surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7929                         // copy only the data requested
7930                         if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
7931                         {
7932                                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7933                                 {
7934                                         if (rsurface.batchvertex3f)
7935                                                 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7936                                         else
7937                                                 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7938                                 }
7939                                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7940                                 {
7941                                         if (rsurface.modelnormal3f)
7942                                                 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7943                                         else
7944                                                 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7945                                 }
7946                                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7947                                 {
7948                                         if (rsurface.modelsvector3f)
7949                                         {
7950                                                 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7951                                                 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7952                                         }
7953                                         else
7954                                         {
7955                                                 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7956                                                 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7957                                         }
7958                                 }
7959                                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7960                                 {
7961                                         if (rsurface.modellightmapcolor4f)
7962                                                 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
7963                                         else
7964                                                 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
7965                                 }
7966                                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7967                                 {
7968                                         if (rsurface.modeltexcoordtexture2f)
7969                                                 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7970                                         else
7971                                                 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7972                                 }
7973                                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7974                                 {
7975                                         if (rsurface.modeltexcoordlightmap2f)
7976                                                 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7977                                         else
7978                                                 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7979                                 }
7980                                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7981                                 {
7982                                         if (rsurface.modelskeletalindex4ub)
7983                                         {
7984                                                 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7985                                                 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7986                                         }
7987                                         else
7988                                         {
7989                                                 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7990                                                 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7991                                                 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
7992                                                 for (j = 0;j < surfacenumvertices;j++)
7993                                                         ub[j*4] = 255;
7994                                         }
7995                                 }
7996                         }
7997                         RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
7998                         numvertices += surfacenumvertices;
7999                         numtriangles += surfacenumtriangles;
8000                 }
8001
8002                 // generate a 16bit index array as well if possible
8003                 // (in general, dynamic batches fit)
8004                 if (numvertices <= 65536)
8005                 {
8006                         rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
8007                         for (i = 0;i < numtriangles*3;i++)
8008                                 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
8009                 }
8010
8011                 // since we've copied everything, the batch now starts at 0
8012                 rsurface.batchfirstvertex = 0;
8013                 rsurface.batchnumvertices = batchnumvertices;
8014                 rsurface.batchfirsttriangle = 0;
8015                 rsurface.batchnumtriangles = batchnumtriangles;
8016         }
8017
8018         // apply skeletal animation that would have been done in the vertex shader
8019         if (rsurface.batchskeletaltransform3x4)
8020         {
8021                 const unsigned char *si;
8022                 const unsigned char *sw;
8023                 const float *t[4];
8024                 const float *b = rsurface.batchskeletaltransform3x4;
8025                 float *vp, *vs, *vt, *vn;
8026                 float w[4];
8027                 float m[3][4], n[3][4];
8028                 float tp[3], ts[3], tt[3], tn[3];
8029                 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
8030                 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
8031                 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
8032                 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
8033                 si = rsurface.batchskeletalindex4ub;
8034                 sw = rsurface.batchskeletalweight4ub;
8035                 vp = rsurface.batchvertex3f;
8036                 vs = rsurface.batchsvector3f;
8037                 vt = rsurface.batchtvector3f;
8038                 vn = rsurface.batchnormal3f;
8039                 memset(m[0], 0, sizeof(m));
8040                 memset(n[0], 0, sizeof(n));
8041                 for (i = 0;i < batchnumvertices;i++)
8042                 {
8043                         t[0] = b + si[0]*12;
8044                         if (sw[0] == 255)
8045                         {
8046                                 // common case - only one matrix
8047                                 m[0][0] = t[0][ 0];
8048                                 m[0][1] = t[0][ 1];
8049                                 m[0][2] = t[0][ 2];
8050                                 m[0][3] = t[0][ 3];
8051                                 m[1][0] = t[0][ 4];
8052                                 m[1][1] = t[0][ 5];
8053                                 m[1][2] = t[0][ 6];
8054                                 m[1][3] = t[0][ 7];
8055                                 m[2][0] = t[0][ 8];
8056                                 m[2][1] = t[0][ 9];
8057                                 m[2][2] = t[0][10];
8058                                 m[2][3] = t[0][11];
8059                         }
8060                         else if (sw[2] + sw[3])
8061                         {
8062                                 // blend 4 matrices
8063                                 t[1] = b + si[1]*12;
8064                                 t[2] = b + si[2]*12;
8065                                 t[3] = b + si[3]*12;
8066                                 w[0] = sw[0] * (1.0f / 255.0f);
8067                                 w[1] = sw[1] * (1.0f / 255.0f);
8068                                 w[2] = sw[2] * (1.0f / 255.0f);
8069                                 w[3] = sw[3] * (1.0f / 255.0f);
8070                                 // blend the matrices
8071                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
8072                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
8073                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
8074                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
8075                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
8076                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
8077                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
8078                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
8079                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
8080                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
8081                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
8082                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
8083                         }
8084                         else
8085                         {
8086                                 // blend 2 matrices
8087                                 t[1] = b + si[1]*12;
8088                                 w[0] = sw[0] * (1.0f / 255.0f);
8089                                 w[1] = sw[1] * (1.0f / 255.0f);
8090                                 // blend the matrices
8091                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
8092                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
8093                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
8094                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
8095                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
8096                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
8097                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
8098                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
8099                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
8100                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
8101                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
8102                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
8103                         }
8104                         si += 4;
8105                         sw += 4;
8106                         // modify the vertex
8107                         VectorCopy(vp, tp);
8108                         vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
8109                         vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
8110                         vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
8111                         vp += 3;
8112                         if (vn)
8113                         {
8114                                 // the normal transformation matrix is a set of cross products...
8115                                 CrossProduct(m[1], m[2], n[0]);
8116                                 CrossProduct(m[2], m[0], n[1]);
8117                                 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8118                                 VectorCopy(vn, tn);
8119                                 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8120                                 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8121                                 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8122                                 VectorNormalize(vn);
8123                                 vn += 3;
8124                                 if (vs)
8125                                 {
8126                                         VectorCopy(vs, ts);
8127                                         vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8128                                         vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8129                                         vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8130                                         VectorNormalize(vs);
8131                                         vs += 3;
8132                                         VectorCopy(vt, tt);
8133                                         vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8134                                         vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8135                                         vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8136                                         VectorNormalize(vt);
8137                                         vt += 3;
8138                                 }
8139                         }
8140                 }
8141                 rsurface.batchskeletaltransform3x4 = NULL;
8142                 rsurface.batchskeletalnumtransforms = 0;
8143         }
8144
8145         // q1bsp surfaces rendered in vertex color mode have to have colors
8146         // calculated based on lightstyles
8147         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
8148         {
8149                 // generate color arrays for the surfaces in this list
8150                 int c[4];
8151                 int scale;
8152                 int size3;
8153                 const int *offsets;
8154                 const unsigned char *lm;
8155                 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8156                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8157                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8158                 numvertices = 0;
8159                 for (i = 0;i < texturenumsurfaces;i++)
8160                 {
8161                         surface = texturesurfacelist[i];
8162                         offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8163                         surfacenumvertices = surface->num_vertices;
8164                         if (surface->lightmapinfo->samples)
8165                         {
8166                                 for (j = 0;j < surfacenumvertices;j++)
8167                                 {
8168                                         lm = surface->lightmapinfo->samples + offsets[j];
8169                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8170                                         VectorScale(lm, scale, c);
8171                                         if (surface->lightmapinfo->styles[1] != 255)
8172                                         {
8173                                                 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8174                                                 lm += size3;
8175                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8176                                                 VectorMA(c, scale, lm, c);
8177                                                 if (surface->lightmapinfo->styles[2] != 255)
8178                                                 {
8179                                                         lm += size3;
8180                                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8181                                                         VectorMA(c, scale, lm, c);
8182                                                         if (surface->lightmapinfo->styles[3] != 255)
8183                                                         {
8184                                                                 lm += size3;
8185                                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8186                                                                 VectorMA(c, scale, lm, c);
8187                                                         }
8188                                                 }
8189                                         }
8190                                         c[0] >>= 7;
8191                                         c[1] >>= 7;
8192                                         c[2] >>= 7;
8193                                         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);
8194                                         numvertices++;
8195                                 }
8196                         }
8197                         else
8198                         {
8199                                 for (j = 0;j < surfacenumvertices;j++)
8200                                 {
8201                                         Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8202                                         numvertices++;
8203                                 }
8204                         }
8205                 }
8206         }
8207
8208         // if vertices are deformed (sprite flares and things in maps, possibly
8209         // water waves, bulges and other deformations), modify the copied vertices
8210         // in place
8211         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8212         {
8213                 float scale;
8214                 switch (deform->deform)
8215                 {
8216                 default:
8217                 case Q3DEFORM_PROJECTIONSHADOW:
8218                 case Q3DEFORM_TEXT0:
8219                 case Q3DEFORM_TEXT1:
8220                 case Q3DEFORM_TEXT2:
8221                 case Q3DEFORM_TEXT3:
8222                 case Q3DEFORM_TEXT4:
8223                 case Q3DEFORM_TEXT5:
8224                 case Q3DEFORM_TEXT6:
8225                 case Q3DEFORM_TEXT7:
8226                 case Q3DEFORM_NONE:
8227                         break;
8228                 case Q3DEFORM_AUTOSPRITE:
8229                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8230                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8231                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8232                         VectorNormalize(newforward);
8233                         VectorNormalize(newright);
8234                         VectorNormalize(newup);
8235 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8236 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8237 //                      rsurface.batchvertex3f_bufferoffset = 0;
8238 //                      rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8239 //                      rsurface.batchsvector3f_vertexbuffer = NULL;
8240 //                      rsurface.batchsvector3f_bufferoffset = 0;
8241 //                      rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8242 //                      rsurface.batchtvector3f_vertexbuffer = NULL;
8243 //                      rsurface.batchtvector3f_bufferoffset = 0;
8244 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8245 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8246 //                      rsurface.batchnormal3f_bufferoffset = 0;
8247                         // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8248                         if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8249                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8250                         if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8251                                 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);
8252                         // a single autosprite surface can contain multiple sprites...
8253                         for (j = 0;j < batchnumvertices - 3;j += 4)
8254                         {
8255                                 VectorClear(center);
8256                                 for (i = 0;i < 4;i++)
8257                                         VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8258                                 VectorScale(center, 0.25f, center);
8259                                 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8260                                 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8261                                 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8262                                 for (i = 0;i < 4;i++)
8263                                 {
8264                                         VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8265                                         VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8266                                 }
8267                         }
8268                         // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8269                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8270                         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);
8271                         break;
8272                 case Q3DEFORM_AUTOSPRITE2:
8273                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8274                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8275                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8276                         VectorNormalize(newforward);
8277                         VectorNormalize(newright);
8278                         VectorNormalize(newup);
8279 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8280 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8281 //                      rsurface.batchvertex3f_bufferoffset = 0;
8282                         {
8283                                 const float *v1, *v2;
8284                                 vec3_t start, end;
8285                                 float f, l;
8286                                 struct
8287                                 {
8288                                         float length2;
8289                                         const float *v1;
8290                                         const float *v2;
8291                                 }
8292                                 shortest[2];
8293                                 memset(shortest, 0, sizeof(shortest));
8294                                 // a single autosprite surface can contain multiple sprites...
8295                                 for (j = 0;j < batchnumvertices - 3;j += 4)
8296                                 {
8297                                         VectorClear(center);
8298                                         for (i = 0;i < 4;i++)
8299                                                 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8300                                         VectorScale(center, 0.25f, center);
8301                                         // find the two shortest edges, then use them to define the
8302                                         // axis vectors for rotating around the central axis
8303                                         for (i = 0;i < 6;i++)
8304                                         {
8305                                                 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8306                                                 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8307                                                 l = VectorDistance2(v1, v2);
8308                                                 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8309                                                 if (v1[2] != v2[2])
8310                                                         l += (1.0f / 1024.0f);
8311                                                 if (shortest[0].length2 > l || i == 0)
8312                                                 {
8313                                                         shortest[1] = shortest[0];
8314                                                         shortest[0].length2 = l;
8315                                                         shortest[0].v1 = v1;
8316                                                         shortest[0].v2 = v2;
8317                                                 }
8318                                                 else if (shortest[1].length2 > l || i == 1)
8319                                                 {
8320                                                         shortest[1].length2 = l;
8321                                                         shortest[1].v1 = v1;
8322                                                         shortest[1].v2 = v2;
8323                                                 }
8324                                         }
8325                                         VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8326                                         VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8327                                         // this calculates the right vector from the shortest edge
8328                                         // and the up vector from the edge midpoints
8329                                         VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8330                                         VectorNormalize(right);
8331                                         VectorSubtract(end, start, up);
8332                                         VectorNormalize(up);
8333                                         // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8334                                         VectorSubtract(rsurface.localvieworigin, center, forward);
8335                                         //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8336                                         VectorNegate(forward, forward);
8337                                         VectorReflect(forward, 0, up, forward);
8338                                         VectorNormalize(forward);
8339                                         CrossProduct(up, forward, newright);
8340                                         VectorNormalize(newright);
8341                                         // rotate the quad around the up axis vector, this is made
8342                                         // especially easy by the fact we know the quad is flat,
8343                                         // so we only have to subtract the center position and
8344                                         // measure distance along the right vector, and then
8345                                         // multiply that by the newright vector and add back the
8346                                         // center position
8347                                         // we also need to subtract the old position to undo the
8348                                         // displacement from the center, which we do with a
8349                                         // DotProduct, the subtraction/addition of center is also
8350                                         // optimized into DotProducts here
8351                                         l = DotProduct(right, center);
8352                                         for (i = 0;i < 4;i++)
8353                                         {
8354                                                 v1 = rsurface.batchvertex3f + 3*(j+i);
8355                                                 f = DotProduct(right, v1) - l;
8356                                                 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8357                                         }
8358                                 }
8359                         }
8360                         if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8361                         {
8362 //                              rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8363 //                              rsurface.batchnormal3f_vertexbuffer = NULL;
8364 //                              rsurface.batchnormal3f_bufferoffset = 0;
8365                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8366                         }
8367                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8368                         {
8369 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8370 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8371 //                              rsurface.batchsvector3f_bufferoffset = 0;
8372 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8373 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8374 //                              rsurface.batchtvector3f_bufferoffset = 0;
8375                                 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);
8376                         }
8377                         break;
8378                 case Q3DEFORM_NORMAL:
8379                         // deform the normals to make reflections wavey
8380                         rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8381                         rsurface.batchnormal3f_vertexbuffer = NULL;
8382                         rsurface.batchnormal3f_bufferoffset = 0;
8383                         for (j = 0;j < batchnumvertices;j++)
8384                         {
8385                                 float vertex[3];
8386                                 float *normal = rsurface.batchnormal3f + 3*j;
8387                                 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8388                                 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8389                                 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8390                                 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8391                                 VectorNormalize(normal);
8392                         }
8393                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8394                         {
8395 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8396 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8397 //                              rsurface.batchsvector3f_bufferoffset = 0;
8398 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8399 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8400 //                              rsurface.batchtvector3f_bufferoffset = 0;
8401                                 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);
8402                         }
8403                         break;
8404                 case Q3DEFORM_WAVE:
8405                         // deform vertex array to make wavey water and flags and such
8406                         waveparms[0] = deform->waveparms[0];
8407                         waveparms[1] = deform->waveparms[1];
8408                         waveparms[2] = deform->waveparms[2];
8409                         waveparms[3] = deform->waveparms[3];
8410                         if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8411                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8412                         // this is how a divisor of vertex influence on deformation
8413                         animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8414                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8415 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8416 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8417 //                      rsurface.batchvertex3f_bufferoffset = 0;
8418 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8419 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8420 //                      rsurface.batchnormal3f_bufferoffset = 0;
8421                         for (j = 0;j < batchnumvertices;j++)
8422                         {
8423                                 // if the wavefunc depends on time, evaluate it per-vertex
8424                                 if (waveparms[3])
8425                                 {
8426                                         waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8427                                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8428                                 }
8429                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8430                         }
8431                         // if we get here, BATCHNEED_ARRAY_NORMAL is 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                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8434                         {
8435 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8436 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8437 //                              rsurface.batchsvector3f_bufferoffset = 0;
8438 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8439 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8440 //                              rsurface.batchtvector3f_bufferoffset = 0;
8441                                 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);
8442                         }
8443                         break;
8444                 case Q3DEFORM_BULGE:
8445                         // deform vertex array to make the surface have moving bulges
8446 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8447 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8448 //                      rsurface.batchvertex3f_bufferoffset = 0;
8449 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8450 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8451 //                      rsurface.batchnormal3f_bufferoffset = 0;
8452                         for (j = 0;j < batchnumvertices;j++)
8453                         {
8454                                 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8455                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8456                         }
8457                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8458                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8459                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8460                         {
8461 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8462 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8463 //                              rsurface.batchsvector3f_bufferoffset = 0;
8464 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8465 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8466 //                              rsurface.batchtvector3f_bufferoffset = 0;
8467                                 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);
8468                         }
8469                         break;
8470                 case Q3DEFORM_MOVE:
8471                         // deform vertex array
8472                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8473                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8474                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8475                         VectorScale(deform->parms, scale, waveparms);
8476 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8477 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8478 //                      rsurface.batchvertex3f_bufferoffset = 0;
8479                         for (j = 0;j < batchnumvertices;j++)
8480                                 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8481                         break;
8482                 }
8483         }
8484
8485         if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8486         {
8487         // generate texcoords based on the chosen texcoord source
8488                 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8489                 {
8490                 default:
8491                 case Q3TCGEN_TEXTURE:
8492                         break;
8493                 case Q3TCGEN_LIGHTMAP:
8494         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8495         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8496         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8497                         if (rsurface.batchtexcoordlightmap2f)
8498                                 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8499                         break;
8500                 case Q3TCGEN_VECTOR:
8501         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8502         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8503         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8504                         for (j = 0;j < batchnumvertices;j++)
8505                         {
8506                                 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8507                                 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8508                         }
8509                         break;
8510                 case Q3TCGEN_ENVIRONMENT:
8511                         // make environment reflections using a spheremap
8512                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8513                         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8514                         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8515                         for (j = 0;j < batchnumvertices;j++)
8516                         {
8517                                 // identical to Q3A's method, but executed in worldspace so
8518                                 // carried models can be shiny too
8519
8520                                 float viewer[3], d, reflected[3], worldreflected[3];
8521
8522                                 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8523                                 // VectorNormalize(viewer);
8524
8525                                 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8526
8527                                 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8528                                 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8529                                 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8530                                 // note: this is proportinal to viewer, so we can normalize later
8531
8532                                 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8533                                 VectorNormalize(worldreflected);
8534
8535                                 // note: this sphere map only uses world x and z!
8536                                 // so positive and negative y will LOOK THE SAME.
8537                                 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8538                                 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8539                         }
8540                         break;
8541                 }
8542                 // the only tcmod that needs software vertex processing is turbulent, so
8543                 // check for it here and apply the changes if needed
8544                 // and we only support that as the first one
8545                 // (handling a mixture of turbulent and other tcmods would be problematic
8546                 //  without punting it entirely to a software path)
8547                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8548                 {
8549                         amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8550                         animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8551         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8552         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8553         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8554                         for (j = 0;j < batchnumvertices;j++)
8555                         {
8556                                 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);
8557                                 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8558                         }
8559                 }
8560         }
8561
8562         // upload buffer data for the dynamic batch
8563         if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicvertex.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo)
8564         {
8565                 if (rsurface.batchvertex3f)
8566                         rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
8567                 if (rsurface.batchsvector3f)
8568                         rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
8569                 if (rsurface.batchtvector3f)
8570                         rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
8571                 if (rsurface.batchnormal3f)
8572                         rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
8573                 if (rsurface.batchlightmapcolor4f)
8574                         rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
8575                 if (rsurface.batchtexcoordtexture2f)
8576                         rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
8577                 if (rsurface.batchtexcoordlightmap2f)
8578                         rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
8579                 if (rsurface.batchskeletalindex4ub)
8580                         rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
8581                 if (rsurface.batchskeletalweight4ub)
8582                         rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
8583                 if (rsurface.batchelement3s)
8584                         rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
8585                 else if (rsurface.batchelement3i)
8586                         rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
8587         }
8588 }
8589
8590 void RSurf_DrawBatch(void)
8591 {
8592         // sometimes a zero triangle surface (usually a degenerate patch) makes it
8593         // through the pipeline, killing it earlier in the pipeline would have
8594         // per-surface overhead rather than per-batch overhead, so it's best to
8595         // reject it here, before it hits glDraw.
8596         if (rsurface.batchnumtriangles == 0)
8597                 return;
8598 #if 0
8599         // batch debugging code
8600         if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8601         {
8602                 int i;
8603                 int j;
8604                 int c;
8605                 const int *e;
8606                 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8607                 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8608                 {
8609                         c = e[i];
8610                         for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8611                         {
8612                                 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8613                                 {
8614                                         if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8615                                                 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);
8616                                         break;
8617                                 }
8618                         }
8619                 }
8620         }
8621 #endif
8622         if (rsurface.batchmultidraw)
8623         {
8624                 // issue multiple draws rather than copying index data
8625                 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8626                 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8627                 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8628                 for (i = 0;i < numsurfaces;)
8629                 {
8630                         // combine consecutive surfaces as one draw
8631                         for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8632                                 if (surfacelist[j] != surfacelist[k] + 1)
8633                                         break;
8634                         firstvertex = surfacelist[i]->num_firstvertex;
8635                         endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8636                         firsttriangle = surfacelist[i]->num_firsttriangle;
8637                         endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8638                         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);
8639                         i = j;
8640                 }
8641         }
8642         else
8643         {
8644                 // there is only one consecutive run of index data (may have been combined)
8645                 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);
8646         }
8647 }
8648
8649 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8650 {
8651         // pick the closest matching water plane
8652         int planeindex, vertexindex, bestplaneindex = -1;
8653         float d, bestd;
8654         vec3_t vert;
8655         const float *v;
8656         r_waterstate_waterplane_t *p;
8657         qboolean prepared = false;
8658         bestd = 0;
8659         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8660         {
8661                 if(p->camera_entity != rsurface.texture->camera_entity)
8662                         continue;
8663                 d = 0;
8664                 if(!prepared)
8665                 {
8666                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8667                         prepared = true;
8668                         if(rsurface.batchnumvertices == 0)
8669                                 break;
8670                 }
8671                 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8672                 {
8673                         Matrix4x4_Transform(&rsurface.matrix, v, vert);
8674                         d += fabs(PlaneDiff(vert, &p->plane));
8675                 }
8676                 if (bestd > d || bestplaneindex < 0)
8677                 {
8678                         bestd = d;
8679                         bestplaneindex = planeindex;
8680                 }
8681         }
8682         return bestplaneindex;
8683         // NOTE: this MAY return a totally unrelated water plane; we can ignore
8684         // this situation though, as it might be better to render single larger
8685         // batches with useless stuff (backface culled for example) than to
8686         // render multiple smaller batches
8687 }
8688
8689 void RSurf_SetupDepthAndCulling(void)
8690 {
8691         // submodels are biased to avoid z-fighting with world surfaces that they
8692         // may be exactly overlapping (avoids z-fighting artifacts on certain
8693         // doors and things in Quake maps)
8694         GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8695         GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8696         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8697         GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8698 }
8699
8700 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8701 {
8702         int i, j;
8703         // transparent sky would be ridiculous
8704         if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8705                 return;
8706         R_SetupShader_Generic_NoTexture(false, false);
8707         skyrenderlater = true;
8708         RSurf_SetupDepthAndCulling();
8709         GL_DepthMask(true);
8710
8711         // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8712         if (r_sky_scissor.integer)
8713         {
8714                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8715                 for (i = 0; i < texturenumsurfaces; i++)
8716                 {
8717                         const msurface_t *surf = texturesurfacelist[i];
8718                         const float *v;
8719                         float p[3];
8720                         float mins[3], maxs[3];
8721                         int scissor[4];
8722                         for (j = 0, v = rsurface.batchvertex3f + 3 * surf->num_firstvertex; j < surf->num_vertices; j++, v += 3)
8723                         {
8724                                 Matrix4x4_Transform(&rsurface.matrix, v, p);
8725                                 if (j > 0)
8726                                 {
8727                                         if (mins[0] > p[0]) mins[0] = p[0];
8728                                         if (mins[1] > p[1]) mins[1] = p[1];
8729                                         if (mins[2] > p[2]) mins[2] = p[2];
8730                                         if (maxs[0] < p[0]) maxs[0] = p[0];
8731                                         if (maxs[1] < p[1]) maxs[1] = p[1];
8732                                         if (maxs[2] < p[2]) maxs[2] = p[2];
8733                                 }
8734                                 else
8735                                 {
8736                                         VectorCopy(p, mins);
8737                                         VectorCopy(p, maxs);
8738                                 }
8739                         }
8740                         if (!R_ScissorForBBox(mins, maxs, scissor))
8741                         {
8742                                 if (skyscissor[2])
8743                                 {
8744                                         if (skyscissor[0] > scissor[0])
8745                                         {
8746                                                 skyscissor[2] += skyscissor[0] - scissor[0];
8747                                                 skyscissor[0] = scissor[0];
8748                                         }
8749                                         if (skyscissor[1] > scissor[1])
8750                                         {
8751                                                 skyscissor[3] += skyscissor[1] - scissor[1];
8752                                                 skyscissor[1] = scissor[1];
8753                                         }
8754                                         if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8755                                                 skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8756                                         if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8757                                                 skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8758                                 }
8759                                 else
8760                                         Vector4Copy(scissor, skyscissor);
8761                         }
8762                 }
8763         }
8764
8765         // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8766         // skymasking on them, and Quake3 never did sky masking (unlike
8767         // software Quake and software Quake2), so disable the sky masking
8768         // in Quake3 maps as it causes problems with q3map2 sky tricks,
8769         // and skymasking also looks very bad when noclipping outside the
8770         // level, so don't use it then either.
8771         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)
8772         {
8773                 R_Mesh_ResetTextureState();
8774                 if (skyrendermasked)
8775                 {
8776                         R_SetupShader_DepthOrShadow(false, false, false);
8777                         // depth-only (masking)
8778                         GL_ColorMask(0, 0, 0, 0);
8779                         // just to make sure that braindead drivers don't draw
8780                         // anything despite that colormask...
8781                         GL_BlendFunc(GL_ZERO, GL_ONE);
8782                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8783                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8784                 }
8785                 else
8786                 {
8787                         R_SetupShader_Generic_NoTexture(false, false);
8788                         // fog sky
8789                         GL_BlendFunc(GL_ONE, GL_ZERO);
8790                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8791                         GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
8792                         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
8793                 }
8794                 RSurf_DrawBatch();
8795                 if (skyrendermasked)
8796                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8797         }
8798         R_Mesh_ResetTextureState();
8799         GL_Color(1, 1, 1, 1);
8800 }
8801
8802 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
8803 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
8804 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
8805 {
8806         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
8807                 return;
8808         if (prepass)
8809         {
8810                 // render screenspace normalmap to texture
8811                 GL_DepthMask(true);
8812                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false);
8813                 RSurf_DrawBatch();
8814                 return;
8815         }
8816
8817         // bind lightmap texture
8818
8819         // water/refraction/reflection/camera surfaces have to be handled specially
8820         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
8821         {
8822                 int start, end, startplaneindex;
8823                 for (start = 0;start < texturenumsurfaces;start = end)
8824                 {
8825                         startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
8826                         if(startplaneindex < 0)
8827                         {
8828                                 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
8829                                 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
8830                                 end = start + 1;
8831                                 continue;
8832                         }
8833                         for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
8834                                 ;
8835                         // now that we have a batch using the same planeindex, render it
8836                         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
8837                         {
8838                                 // render water or distortion background
8839                                 GL_DepthMask(true);
8840                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8841                                 RSurf_DrawBatch();
8842                                 // blend surface on top
8843                                 GL_DepthMask(false);
8844                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false);
8845                                 RSurf_DrawBatch();
8846                         }
8847                         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
8848                         {
8849                                 // render surface with reflection texture as input
8850                                 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8851                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8852                                 RSurf_DrawBatch();
8853                         }
8854                 }
8855                 return;
8856         }
8857
8858         // render surface batch normally
8859         GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8860         R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0);
8861         RSurf_DrawBatch();
8862 }
8863
8864 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
8865 {
8866         int vi;
8867         int j;
8868         int texturesurfaceindex;
8869         int k;
8870         const msurface_t *surface;
8871         float surfacecolor4f[4];
8872
8873 //      R_Mesh_ResetTextureState();
8874         R_SetupShader_Generic_NoTexture(false, false);
8875
8876         GL_BlendFunc(GL_ONE, GL_ZERO);
8877         GL_DepthMask(writedepth);
8878
8879         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
8880         vi = 0;
8881         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8882         {
8883                 surface = texturesurfacelist[texturesurfaceindex];
8884                 k = (int)(((size_t)surface) / sizeof(msurface_t));
8885                 Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
8886                 for (j = 0;j < surface->num_vertices;j++)
8887                 {
8888                         Vector4Copy(surfacecolor4f, rsurface.batchlightmapcolor4f + 4 * vi);
8889                         vi++;
8890                 }
8891         }
8892         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchlightmapcolor4f, rsurface.batchtexcoordtexture2f);
8893         RSurf_DrawBatch();
8894 }
8895
8896 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
8897 {
8898         CHECKGLERROR
8899         RSurf_SetupDepthAndCulling();
8900         if (r_showsurfaces.integer && r_refdef.view.showdebug)
8901         {
8902                 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
8903                 return;
8904         }
8905         switch (vid.renderpath)
8906         {
8907         case RENDERPATH_GL20:
8908         case RENDERPATH_GLES2:
8909                 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
8910                 break;
8911         }
8912         CHECKGLERROR
8913 }
8914
8915 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
8916 {
8917         int i, j;
8918         int texturenumsurfaces, endsurface;
8919         texture_t *texture;
8920         const msurface_t *surface;
8921         const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
8922
8923         RSurf_ActiveModelEntity(ent, true, true, false);
8924
8925         if (r_transparentdepthmasking.integer)
8926         {
8927                 qboolean setup = false;
8928                 for (i = 0;i < numsurfaces;i = j)
8929                 {
8930                         j = i + 1;
8931                         surface = rsurface.modelsurfaces + surfacelist[i];
8932                         texture = surface->texture;
8933                         rsurface.texture = R_GetCurrentTexture(texture);
8934                         rsurface.lightmaptexture = NULL;
8935                         rsurface.deluxemaptexture = NULL;
8936                         rsurface.uselightmaptexture = false;
8937                         // scan ahead until we find a different texture
8938                         endsurface = min(i + 1024, numsurfaces);
8939                         texturenumsurfaces = 0;
8940                         texturesurfacelist[texturenumsurfaces++] = surface;
8941                         for (;j < endsurface;j++)
8942                         {
8943                                 surface = rsurface.modelsurfaces + surfacelist[j];
8944                                 if (texture != surface->texture)
8945                                         break;
8946                                 texturesurfacelist[texturenumsurfaces++] = surface;
8947                         }
8948                         if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
8949                                 continue;
8950                         // render the range of surfaces as depth
8951                         if (!setup)
8952                         {
8953                                 setup = true;
8954                                 GL_ColorMask(0,0,0,0);
8955                                 GL_Color(1,1,1,1);
8956                                 GL_DepthTest(true);
8957                                 GL_BlendFunc(GL_ONE, GL_ZERO);
8958                                 GL_DepthMask(true);
8959 //                              R_Mesh_ResetTextureState();
8960                         }
8961                         RSurf_SetupDepthAndCulling();
8962                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8963                         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8964                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8965                         RSurf_DrawBatch();
8966                 }
8967                 if (setup)
8968                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8969         }
8970
8971         for (i = 0;i < numsurfaces;i = j)
8972         {
8973                 j = i + 1;
8974                 surface = rsurface.modelsurfaces + surfacelist[i];
8975                 texture = surface->texture;
8976                 rsurface.texture = R_GetCurrentTexture(texture);
8977                 // scan ahead until we find a different texture
8978                 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
8979                 texturenumsurfaces = 0;
8980                 texturesurfacelist[texturenumsurfaces++] = surface;
8981                 if(FAKELIGHT_ENABLED)
8982                 {
8983                         rsurface.lightmaptexture = NULL;
8984                         rsurface.deluxemaptexture = NULL;
8985                         rsurface.uselightmaptexture = false;
8986                         for (;j < endsurface;j++)
8987                         {
8988                                 surface = rsurface.modelsurfaces + surfacelist[j];
8989                                 if (texture != surface->texture)
8990                                         break;
8991                                 texturesurfacelist[texturenumsurfaces++] = surface;
8992                         }
8993                 }
8994                 else
8995                 {
8996                         rsurface.lightmaptexture = surface->lightmaptexture;
8997                         rsurface.deluxemaptexture = surface->deluxemaptexture;
8998                         rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
8999                         for (;j < endsurface;j++)
9000                         {
9001                                 surface = rsurface.modelsurfaces + surfacelist[j];
9002                                 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
9003                                         break;
9004                                 texturesurfacelist[texturenumsurfaces++] = surface;
9005                         }
9006                 }
9007                 // render the range of surfaces
9008                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false);
9009         }
9010         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
9011 }
9012
9013 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9014 {
9015         // transparent surfaces get pushed off into the transparent queue
9016         int surfacelistindex;
9017         const msurface_t *surface;
9018         vec3_t tempcenter, center;
9019         for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
9020         {
9021                 surface = texturesurfacelist[surfacelistindex];
9022                 if (r_transparent_sortsurfacesbynearest.integer)
9023                 {
9024                         tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
9025                         tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
9026                         tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
9027                 }
9028                 else
9029                 {
9030                         tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
9031                         tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
9032                         tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
9033                 }
9034                 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
9035                 if (rsurface.entity->transparent_offset) // transparent offset
9036                 {
9037                         center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
9038                         center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
9039                         center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
9040                 }
9041                 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);
9042         }
9043 }
9044
9045 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9046 {
9047         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
9048                 return;
9049         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
9050                 return;
9051         RSurf_SetupDepthAndCulling();
9052         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9053         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9054         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9055         RSurf_DrawBatch();
9056 }
9057
9058 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass)
9059 {
9060         CHECKGLERROR
9061         if (depthonly)
9062                 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
9063         else if (prepass)
9064         {
9065                 if (!rsurface.texture->currentnumlayers)
9066                         return;
9067                 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
9068                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9069                 else
9070                         R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
9071         }
9072         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
9073                 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
9074         else if (!rsurface.texture->currentnumlayers)
9075                 return;
9076         else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
9077         {
9078                 // in the deferred case, transparent surfaces were queued during prepass
9079                 if (!r_shadow_usingdeferredprepass)
9080                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9081         }
9082         else
9083         {
9084                 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
9085                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass);
9086         }
9087         CHECKGLERROR
9088 }
9089
9090 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass)
9091 {
9092         int i, j;
9093         texture_t *texture;
9094         R_FrameData_SetMark();
9095         // break the surface list down into batches by texture and use of lightmapping
9096         for (i = 0;i < numsurfaces;i = j)
9097         {
9098                 j = i + 1;
9099                 // texture is the base texture pointer, rsurface.texture is the
9100                 // current frame/skin the texture is directing us to use (for example
9101                 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
9102                 // use skin 1 instead)
9103                 texture = surfacelist[i]->texture;
9104                 rsurface.texture = R_GetCurrentTexture(texture);
9105                 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
9106                 {
9107                         // if this texture is not the kind we want, skip ahead to the next one
9108                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9109                                 ;
9110                         continue;
9111                 }
9112                 if(FAKELIGHT_ENABLED || depthonly || prepass)
9113                 {
9114                         rsurface.lightmaptexture = NULL;
9115                         rsurface.deluxemaptexture = NULL;
9116                         rsurface.uselightmaptexture = false;
9117                         // simply scan ahead until we find a different texture or lightmap state
9118                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9119                                 ;
9120                 }
9121                 else
9122                 {
9123                         rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
9124                         rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
9125                         rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
9126                         // simply scan ahead until we find a different texture or lightmap state
9127                         for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
9128                                 ;
9129                 }
9130                 // render the range of surfaces
9131                 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass);
9132         }
9133         R_FrameData_ReturnToMark();
9134 }
9135
9136 float locboxvertex3f[6*4*3] =
9137 {
9138         1,0,1, 1,0,0, 1,1,0, 1,1,1,
9139         0,1,1, 0,1,0, 0,0,0, 0,0,1,
9140         1,1,1, 1,1,0, 0,1,0, 0,1,1,
9141         0,0,1, 0,0,0, 1,0,0, 1,0,1,
9142         0,0,1, 1,0,1, 1,1,1, 0,1,1,
9143         1,0,0, 0,0,0, 0,1,0, 1,1,0
9144 };
9145
9146 unsigned short locboxelements[6*2*3] =
9147 {
9148          0, 1, 2, 0, 2, 3,
9149          4, 5, 6, 4, 6, 7,
9150          8, 9,10, 8,10,11,
9151         12,13,14, 12,14,15,
9152         16,17,18, 16,18,19,
9153         20,21,22, 20,22,23
9154 };
9155
9156 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9157 {
9158         int i, j;
9159         cl_locnode_t *loc = (cl_locnode_t *)ent;
9160         vec3_t mins, size;
9161         float vertex3f[6*4*3];
9162         CHECKGLERROR
9163         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9164         GL_DepthMask(false);
9165         GL_DepthRange(0, 1);
9166         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9167         GL_DepthTest(true);
9168         GL_CullFace(GL_NONE);
9169         R_EntityMatrix(&identitymatrix);
9170
9171 //      R_Mesh_ResetTextureState();
9172
9173         i = surfacelist[0];
9174         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9175                          ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9176                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9177                         surfacelist[0] < 0 ? 0.5f : 0.125f);
9178
9179         if (VectorCompare(loc->mins, loc->maxs))
9180         {
9181                 VectorSet(size, 2, 2, 2);
9182                 VectorMA(loc->mins, -0.5f, size, mins);
9183         }
9184         else
9185         {
9186                 VectorCopy(loc->mins, mins);
9187                 VectorSubtract(loc->maxs, loc->mins, size);
9188         }
9189
9190         for (i = 0;i < 6*4*3;)
9191                 for (j = 0;j < 3;j++, i++)
9192                         vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9193
9194         R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9195         R_SetupShader_Generic_NoTexture(false, false);
9196         R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9197 }
9198
9199 void R_DrawLocs(void)
9200 {
9201         int index;
9202         cl_locnode_t *loc, *nearestloc;
9203         vec3_t center;
9204         nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9205         for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9206         {
9207                 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9208                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9209         }
9210 }
9211
9212 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9213 {
9214         if (decalsystem->decals)
9215                 Mem_Free(decalsystem->decals);
9216         memset(decalsystem, 0, sizeof(*decalsystem));
9217 }
9218
9219 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)
9220 {
9221         tridecal_t *decal;
9222         tridecal_t *decals;
9223         int i;
9224
9225         // expand or initialize the system
9226         if (decalsystem->maxdecals <= decalsystem->numdecals)
9227         {
9228                 decalsystem_t old = *decalsystem;
9229                 qboolean useshortelements;
9230                 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9231                 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9232                 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)));
9233                 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9234                 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9235                 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9236                 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9237                 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9238                 if (decalsystem->numdecals)
9239                         memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9240                 if (old.decals)
9241                         Mem_Free(old.decals);
9242                 for (i = 0;i < decalsystem->maxdecals*3;i++)
9243                         decalsystem->element3i[i] = i;
9244                 if (useshortelements)
9245                         for (i = 0;i < decalsystem->maxdecals*3;i++)
9246                                 decalsystem->element3s[i] = i;
9247         }
9248
9249         // grab a decal and search for another free slot for the next one
9250         decals = decalsystem->decals;
9251         decal = decalsystem->decals + (i = decalsystem->freedecal++);
9252         for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9253                 ;
9254         decalsystem->freedecal = i;
9255         if (decalsystem->numdecals <= i)
9256                 decalsystem->numdecals = i + 1;
9257
9258         // initialize the decal
9259         decal->lived = 0;
9260         decal->triangleindex = triangleindex;
9261         decal->surfaceindex = surfaceindex;
9262         decal->decalsequence = decalsequence;
9263         decal->color4f[0][0] = c0[0];
9264         decal->color4f[0][1] = c0[1];
9265         decal->color4f[0][2] = c0[2];
9266         decal->color4f[0][3] = 1;
9267         decal->color4f[1][0] = c1[0];
9268         decal->color4f[1][1] = c1[1];
9269         decal->color4f[1][2] = c1[2];
9270         decal->color4f[1][3] = 1;
9271         decal->color4f[2][0] = c2[0];
9272         decal->color4f[2][1] = c2[1];
9273         decal->color4f[2][2] = c2[2];
9274         decal->color4f[2][3] = 1;
9275         decal->vertex3f[0][0] = v0[0];
9276         decal->vertex3f[0][1] = v0[1];
9277         decal->vertex3f[0][2] = v0[2];
9278         decal->vertex3f[1][0] = v1[0];
9279         decal->vertex3f[1][1] = v1[1];
9280         decal->vertex3f[1][2] = v1[2];
9281         decal->vertex3f[2][0] = v2[0];
9282         decal->vertex3f[2][1] = v2[1];
9283         decal->vertex3f[2][2] = v2[2];
9284         decal->texcoord2f[0][0] = t0[0];
9285         decal->texcoord2f[0][1] = t0[1];
9286         decal->texcoord2f[1][0] = t1[0];
9287         decal->texcoord2f[1][1] = t1[1];
9288         decal->texcoord2f[2][0] = t2[0];
9289         decal->texcoord2f[2][1] = t2[1];
9290         TriangleNormal(v0, v1, v2, decal->plane);
9291         VectorNormalize(decal->plane);
9292         decal->plane[3] = DotProduct(v0, decal->plane);
9293 }
9294
9295 extern cvar_t cl_decals_bias;
9296 extern cvar_t cl_decals_models;
9297 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9298 // baseparms, parms, temps
9299 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)
9300 {
9301         int cornerindex;
9302         int index;
9303         float v[9][3];
9304         const float *vertex3f;
9305         const float *normal3f;
9306         int numpoints;
9307         float points[2][9][3];
9308         float temp[3];
9309         float tc[9][2];
9310         float f;
9311         float c[9][4];
9312         const int *e;
9313
9314         e = rsurface.modelelement3i + 3*triangleindex;
9315
9316         vertex3f = rsurface.modelvertex3f;
9317         normal3f = rsurface.modelnormal3f;
9318
9319         if (normal3f)
9320         {
9321                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9322                 {
9323                         index = 3*e[cornerindex];
9324                         VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9325                 }
9326         }
9327         else
9328         {
9329                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9330                 {
9331                         index = 3*e[cornerindex];
9332                         VectorCopy(vertex3f + index, v[cornerindex]);
9333                 }
9334         }
9335
9336         // cull backfaces
9337         //TriangleNormal(v[0], v[1], v[2], normal);
9338         //if (DotProduct(normal, localnormal) < 0.0f)
9339         //      continue;
9340         // clip by each of the box planes formed from the projection matrix
9341         // if anything survives, we emit the decal
9342         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]);
9343         if (numpoints < 3)
9344                 return;
9345         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]);
9346         if (numpoints < 3)
9347                 return;
9348         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]);
9349         if (numpoints < 3)
9350                 return;
9351         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]);
9352         if (numpoints < 3)
9353                 return;
9354         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]);
9355         if (numpoints < 3)
9356                 return;
9357         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]);
9358         if (numpoints < 3)
9359                 return;
9360         // some part of the triangle survived, so we have to accept it...
9361         if (dynamic)
9362         {
9363                 // dynamic always uses the original triangle
9364                 numpoints = 3;
9365                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9366                 {
9367                         index = 3*e[cornerindex];
9368                         VectorCopy(vertex3f + index, v[cornerindex]);
9369                 }
9370         }
9371         for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9372         {
9373                 // convert vertex positions to texcoords
9374                 Matrix4x4_Transform(projection, v[cornerindex], temp);
9375                 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9376                 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9377                 // calculate distance fade from the projection origin
9378                 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9379                 f = bound(0.0f, f, 1.0f);
9380                 c[cornerindex][0] = r * f;
9381                 c[cornerindex][1] = g * f;
9382                 c[cornerindex][2] = b * f;
9383                 c[cornerindex][3] = 1.0f;
9384                 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9385         }
9386         if (dynamic)
9387                 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);
9388         else
9389                 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9390                         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);
9391 }
9392 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)
9393 {
9394         matrix4x4_t projection;
9395         decalsystem_t *decalsystem;
9396         qboolean dynamic;
9397         dp_model_t *model;
9398         const msurface_t *surface;
9399         const msurface_t *surfaces;
9400         const int *surfacelist;
9401         const texture_t *texture;
9402         int numtriangles;
9403         int numsurfacelist;
9404         int surfacelistindex;
9405         int surfaceindex;
9406         int triangleindex;
9407         float localorigin[3];
9408         float localnormal[3];
9409         float localmins[3];
9410         float localmaxs[3];
9411         float localsize;
9412         //float normal[3];
9413         float planes[6][4];
9414         float angles[3];
9415         bih_t *bih;
9416         int bih_triangles_count;
9417         int bih_triangles[256];
9418         int bih_surfaces[256];
9419
9420         decalsystem = &ent->decalsystem;
9421         model = ent->model;
9422         if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9423         {
9424                 R_DecalSystem_Reset(&ent->decalsystem);
9425                 return;
9426         }
9427
9428         if (!model->brush.data_leafs && !cl_decals_models.integer)
9429         {
9430                 if (decalsystem->model)
9431                         R_DecalSystem_Reset(decalsystem);
9432                 return;
9433         }
9434
9435         if (decalsystem->model != model)
9436                 R_DecalSystem_Reset(decalsystem);
9437         decalsystem->model = model;
9438
9439         RSurf_ActiveModelEntity(ent, true, false, false);
9440
9441         Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9442         Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9443         VectorNormalize(localnormal);
9444         localsize = worldsize*rsurface.inversematrixscale;
9445         localmins[0] = localorigin[0] - localsize;
9446         localmins[1] = localorigin[1] - localsize;
9447         localmins[2] = localorigin[2] - localsize;
9448         localmaxs[0] = localorigin[0] + localsize;
9449         localmaxs[1] = localorigin[1] + localsize;
9450         localmaxs[2] = localorigin[2] + localsize;
9451
9452         //VectorCopy(localnormal, planes[4]);
9453         //VectorVectors(planes[4], planes[2], planes[0]);
9454         AnglesFromVectors(angles, localnormal, NULL, false);
9455         AngleVectors(angles, planes[0], planes[2], planes[4]);
9456         VectorNegate(planes[0], planes[1]);
9457         VectorNegate(planes[2], planes[3]);
9458         VectorNegate(planes[4], planes[5]);
9459         planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9460         planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9461         planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9462         planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9463         planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9464         planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9465
9466 #if 1
9467 // works
9468 {
9469         matrix4x4_t forwardprojection;
9470         Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9471         Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9472 }
9473 #else
9474 // broken
9475 {
9476         float projectionvector[4][3];
9477         VectorScale(planes[0], ilocalsize, projectionvector[0]);
9478         VectorScale(planes[2], ilocalsize, projectionvector[1]);
9479         VectorScale(planes[4], ilocalsize, projectionvector[2]);
9480         projectionvector[0][0] = planes[0][0] * ilocalsize;
9481         projectionvector[0][1] = planes[1][0] * ilocalsize;
9482         projectionvector[0][2] = planes[2][0] * ilocalsize;
9483         projectionvector[1][0] = planes[0][1] * ilocalsize;
9484         projectionvector[1][1] = planes[1][1] * ilocalsize;
9485         projectionvector[1][2] = planes[2][1] * ilocalsize;
9486         projectionvector[2][0] = planes[0][2] * ilocalsize;
9487         projectionvector[2][1] = planes[1][2] * ilocalsize;
9488         projectionvector[2][2] = planes[2][2] * ilocalsize;
9489         projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9490         projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9491         projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9492         Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9493 }
9494 #endif
9495
9496         dynamic = model->surfmesh.isanimated;
9497         numsurfacelist = model->nummodelsurfaces;
9498         surfacelist = model->sortedmodelsurfaces;
9499         surfaces = model->data_surfaces;
9500
9501         bih = NULL;
9502         bih_triangles_count = -1;
9503         if(!dynamic)
9504         {
9505                 if(model->render_bih.numleafs)
9506                         bih = &model->render_bih;
9507                 else if(model->collision_bih.numleafs)
9508                         bih = &model->collision_bih;
9509         }
9510         if(bih)
9511                 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9512         if(bih_triangles_count == 0)
9513                 return;
9514         if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9515                 return;
9516         if(bih_triangles_count > 0)
9517         {
9518                 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9519                 {
9520                         surfaceindex = bih_surfaces[triangleindex];
9521                         surface = surfaces + surfaceindex;
9522                         texture = surface->texture;
9523                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9524                                 continue;
9525                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9526                                 continue;
9527                         R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9528                 }
9529         }
9530         else
9531         {
9532                 for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
9533                 {
9534                         surfaceindex = surfacelist[surfacelistindex];
9535                         surface = surfaces + surfaceindex;
9536                         // check cull box first because it rejects more than any other check
9537                         if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9538                                 continue;
9539                         // skip transparent surfaces
9540                         texture = surface->texture;
9541                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9542                                 continue;
9543                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9544                                 continue;
9545                         numtriangles = surface->num_triangles;
9546                         for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9547                                 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9548                 }
9549         }
9550 }
9551
9552 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9553 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)
9554 {
9555         int renderentityindex;
9556         float worldmins[3];
9557         float worldmaxs[3];
9558         entity_render_t *ent;
9559
9560         if (!cl_decals_newsystem.integer)
9561                 return;
9562
9563         worldmins[0] = worldorigin[0] - worldsize;
9564         worldmins[1] = worldorigin[1] - worldsize;
9565         worldmins[2] = worldorigin[2] - worldsize;
9566         worldmaxs[0] = worldorigin[0] + worldsize;
9567         worldmaxs[1] = worldorigin[1] + worldsize;
9568         worldmaxs[2] = worldorigin[2] + worldsize;
9569
9570         R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9571
9572         for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9573         {
9574                 ent = r_refdef.scene.entities[renderentityindex];
9575                 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9576                         continue;
9577
9578                 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9579         }
9580 }
9581
9582 typedef struct r_decalsystem_splatqueue_s
9583 {
9584         vec3_t worldorigin;
9585         vec3_t worldnormal;
9586         float color[4];
9587         float tcrange[4];
9588         float worldsize;
9589         unsigned int decalsequence;
9590 }
9591 r_decalsystem_splatqueue_t;
9592
9593 int r_decalsystem_numqueued = 0;
9594 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9595
9596 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)
9597 {
9598         r_decalsystem_splatqueue_t *queue;
9599
9600         if (!cl_decals_newsystem.integer || r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9601                 return;
9602
9603         queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9604         VectorCopy(worldorigin, queue->worldorigin);
9605         VectorCopy(worldnormal, queue->worldnormal);
9606         Vector4Set(queue->color, r, g, b, a);
9607         Vector4Set(queue->tcrange, s1, t1, s2, t2);
9608         queue->worldsize = worldsize;
9609         queue->decalsequence = cl.decalsequence++;
9610 }
9611
9612 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9613 {
9614         int i;
9615         r_decalsystem_splatqueue_t *queue;
9616
9617         for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9618                 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);
9619         r_decalsystem_numqueued = 0;
9620 }
9621
9622 extern cvar_t cl_decals_max;
9623 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9624 {
9625         int i;
9626         decalsystem_t *decalsystem = &ent->decalsystem;
9627         int numdecals;
9628         unsigned int killsequence;
9629         tridecal_t *decal;
9630         float frametime;
9631         float lifetime;
9632
9633         if (!decalsystem->numdecals)
9634                 return;
9635
9636         if (r_showsurfaces.integer)
9637                 return;
9638
9639         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9640         {
9641                 R_DecalSystem_Reset(decalsystem);
9642                 return;
9643         }
9644
9645         killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9646         lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9647
9648         if (decalsystem->lastupdatetime)
9649                 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9650         else
9651                 frametime = 0;
9652         decalsystem->lastupdatetime = r_refdef.scene.time;
9653         numdecals = decalsystem->numdecals;
9654
9655         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9656         {
9657                 if (decal->color4f[0][3])
9658                 {
9659                         decal->lived += frametime;
9660                         if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9661                         {
9662                                 memset(decal, 0, sizeof(*decal));
9663                                 if (decalsystem->freedecal > i)
9664                                         decalsystem->freedecal = i;
9665                         }
9666                 }
9667         }
9668         decal = decalsystem->decals;
9669         while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9670                 numdecals--;
9671
9672         // collapse the array by shuffling the tail decals into the gaps
9673         for (;;)
9674         {
9675                 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
9676                         decalsystem->freedecal++;
9677                 if (decalsystem->freedecal == numdecals)
9678                         break;
9679                 decal[decalsystem->freedecal] = decal[--numdecals];
9680         }
9681
9682         decalsystem->numdecals = numdecals;
9683
9684         if (numdecals <= 0)
9685         {
9686                 // if there are no decals left, reset decalsystem
9687                 R_DecalSystem_Reset(decalsystem);
9688         }
9689 }
9690
9691 extern skinframe_t *decalskinframe;
9692 static void R_DrawModelDecals_Entity(entity_render_t *ent)
9693 {
9694         int i;
9695         decalsystem_t *decalsystem = &ent->decalsystem;
9696         int numdecals;
9697         tridecal_t *decal;
9698         float faderate;
9699         float alpha;
9700         float *v3f;
9701         float *c4f;
9702         float *t2f;
9703         const int *e;
9704         const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
9705         int numtris = 0;
9706
9707         numdecals = decalsystem->numdecals;
9708         if (!numdecals)
9709                 return;
9710
9711         if (r_showsurfaces.integer)
9712                 return;
9713
9714         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9715         {
9716                 R_DecalSystem_Reset(decalsystem);
9717                 return;
9718         }
9719
9720         // if the model is static it doesn't matter what value we give for
9721         // wantnormals and wanttangents, so this logic uses only rules applicable
9722         // to a model, knowing that they are meaningless otherwise
9723         RSurf_ActiveModelEntity(ent, false, false, false);
9724
9725         decalsystem->lastupdatetime = r_refdef.scene.time;
9726
9727         faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
9728
9729         // update vertex positions for animated models
9730         v3f = decalsystem->vertex3f;
9731         c4f = decalsystem->color4f;
9732         t2f = decalsystem->texcoord2f;
9733         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9734         {
9735                 if (!decal->color4f[0][3])
9736                         continue;
9737
9738                 if (surfacevisible && !surfacevisible[decal->surfaceindex])
9739                         continue;
9740
9741                 // skip backfaces
9742                 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
9743                         continue;
9744
9745                 // update color values for fading decals
9746                 if (decal->lived >= cl_decals_time.value)
9747                         alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
9748                 else
9749                         alpha = 1.0f;
9750
9751                 c4f[ 0] = decal->color4f[0][0] * alpha;
9752                 c4f[ 1] = decal->color4f[0][1] * alpha;
9753                 c4f[ 2] = decal->color4f[0][2] * alpha;
9754                 c4f[ 3] = 1;
9755                 c4f[ 4] = decal->color4f[1][0] * alpha;
9756                 c4f[ 5] = decal->color4f[1][1] * alpha;
9757                 c4f[ 6] = decal->color4f[1][2] * alpha;
9758                 c4f[ 7] = 1;
9759                 c4f[ 8] = decal->color4f[2][0] * alpha;
9760                 c4f[ 9] = decal->color4f[2][1] * alpha;
9761                 c4f[10] = decal->color4f[2][2] * alpha;
9762                 c4f[11] = 1;
9763
9764                 t2f[0] = decal->texcoord2f[0][0];
9765                 t2f[1] = decal->texcoord2f[0][1];
9766                 t2f[2] = decal->texcoord2f[1][0];
9767                 t2f[3] = decal->texcoord2f[1][1];
9768                 t2f[4] = decal->texcoord2f[2][0];
9769                 t2f[5] = decal->texcoord2f[2][1];
9770
9771                 // update vertex positions for animated models
9772                 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
9773                 {
9774                         e = rsurface.modelelement3i + 3*decal->triangleindex;
9775                         VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
9776                         VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
9777                         VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
9778                 }
9779                 else
9780                 {
9781                         VectorCopy(decal->vertex3f[0], v3f);
9782                         VectorCopy(decal->vertex3f[1], v3f + 3);
9783                         VectorCopy(decal->vertex3f[2], v3f + 6);
9784                 }
9785
9786                 if (r_refdef.fogenabled)
9787                 {
9788                         alpha = RSurf_FogVertex(v3f);
9789                         VectorScale(c4f, alpha, c4f);
9790                         alpha = RSurf_FogVertex(v3f + 3);
9791                         VectorScale(c4f + 4, alpha, c4f + 4);
9792                         alpha = RSurf_FogVertex(v3f + 6);
9793                         VectorScale(c4f + 8, alpha, c4f + 8);
9794                 }
9795
9796                 v3f += 9;
9797                 c4f += 12;
9798                 t2f += 6;
9799                 numtris++;
9800         }
9801
9802         if (numtris > 0)
9803         {
9804                 r_refdef.stats[r_stat_drawndecals] += numtris;
9805
9806                 // now render the decals all at once
9807                 // (this assumes they all use one particle font texture!)
9808                 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);
9809 //              R_Mesh_ResetTextureState();
9810                 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
9811                 GL_DepthMask(false);
9812                 GL_DepthRange(0, 1);
9813                 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
9814                 GL_DepthTest(true);
9815                 GL_CullFace(GL_NONE);
9816                 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
9817                 R_SetupShader_Generic(decalskinframe->base, false, false, false);
9818                 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
9819         }
9820 }
9821
9822 static void R_DrawModelDecals(void)
9823 {
9824         int i, numdecals;
9825
9826         // fade faster when there are too many decals
9827         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9828         for (i = 0;i < r_refdef.scene.numentities;i++)
9829                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9830
9831         R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
9832         for (i = 0;i < r_refdef.scene.numentities;i++)
9833                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9834                         R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
9835
9836         R_DecalSystem_ApplySplatEntitiesQueue();
9837
9838         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9839         for (i = 0;i < r_refdef.scene.numentities;i++)
9840                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9841
9842         r_refdef.stats[r_stat_totaldecals] += numdecals;
9843
9844         if (r_showsurfaces.integer)
9845                 return;
9846
9847         R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
9848
9849         for (i = 0;i < r_refdef.scene.numentities;i++)
9850         {
9851                 if (!r_refdef.viewcache.entityvisible[i])
9852                         continue;
9853                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9854                         R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
9855         }
9856 }
9857
9858 extern cvar_t mod_collision_bih;
9859 static void R_DrawDebugModel(void)
9860 {
9861         entity_render_t *ent = rsurface.entity;
9862         int i, j, flagsmask;
9863         const msurface_t *surface;
9864         dp_model_t *model = ent->model;
9865
9866         if (!sv.active  && !cls.demoplayback && ent != r_refdef.scene.worldentity)
9867                 return;
9868
9869         if (r_showoverdraw.value > 0)
9870         {
9871                 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
9872                 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9873                 R_SetupShader_Generic_NoTexture(false, false);
9874                 GL_DepthTest(false);
9875                 GL_DepthMask(false);
9876                 GL_DepthRange(0, 1);
9877                 GL_BlendFunc(GL_ONE, GL_ONE);
9878                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9879                 {
9880                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9881                                 continue;
9882                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9883                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9884                         {
9885                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
9886                                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
9887                                 if (!rsurface.texture->currentlayers->depthmask)
9888                                         GL_Color(c, 0, 0, 1.0f);
9889                                 else if (ent == r_refdef.scene.worldentity)
9890                                         GL_Color(c, c, c, 1.0f);
9891                                 else
9892                                         GL_Color(0, c, 0, 1.0f);
9893                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9894                                 RSurf_DrawBatch();
9895                         }
9896                 }
9897                 rsurface.texture = NULL;
9898         }
9899
9900         flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9901
9902 //      R_Mesh_ResetTextureState();
9903         R_SetupShader_Generic_NoTexture(false, false);
9904         GL_DepthRange(0, 1);
9905         GL_DepthTest(!r_showdisabledepthtest.integer);
9906         GL_DepthMask(false);
9907         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9908
9909         if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
9910         {
9911                 int triangleindex;
9912                 int bihleafindex;
9913                 qboolean cullbox = false;
9914                 const q3mbrush_t *brush;
9915                 const bih_t *bih = &model->collision_bih;
9916                 const bih_leaf_t *bihleaf;
9917                 float vertex3f[3][3];
9918                 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
9919                 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
9920                 {
9921                         if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
9922                                 continue;
9923                         switch (bihleaf->type)
9924                         {
9925                         case BIH_BRUSH:
9926                                 brush = model->brush.data_brushes + bihleaf->itemindex;
9927                                 if (brush->colbrushf && brush->colbrushf->numtriangles)
9928                                 {
9929                                         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);
9930                                         R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
9931                                         R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
9932                                 }
9933                                 break;
9934                         case BIH_COLLISIONTRIANGLE:
9935                                 triangleindex = bihleaf->itemindex;
9936                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
9937                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
9938                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
9939                                 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);
9940                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9941                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9942                                 break;
9943                         case BIH_RENDERTRIANGLE:
9944                                 triangleindex = bihleaf->itemindex;
9945                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
9946                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
9947                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
9948                                 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);
9949                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9950                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9951                                 break;
9952                         }
9953                 }
9954         }
9955
9956         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9957
9958 #ifndef USE_GLES2
9959         if (r_showtris.value > 0 && qglPolygonMode)
9960         {
9961                 if (r_showdisabledepthtest.integer)
9962                 {
9963                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9964                         GL_DepthMask(false);
9965                 }
9966                 else
9967                 {
9968                         GL_BlendFunc(GL_ONE, GL_ZERO);
9969                         GL_DepthMask(true);
9970                 }
9971                 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
9972                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9973                 {
9974                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9975                                 continue;
9976                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9977                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9978                         {
9979                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9980                                 if (!rsurface.texture->currentlayers->depthmask)
9981                                         GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
9982                                 else if (ent == r_refdef.scene.worldentity)
9983                                         GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
9984                                 else
9985                                         GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
9986                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9987                                 RSurf_DrawBatch();
9988                         }
9989                 }
9990                 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
9991                 rsurface.texture = NULL;
9992         }
9993
9994 # if 0
9995         // FIXME!  implement r_shownormals with just triangles
9996         if (r_shownormals.value != 0 && qglBegin)
9997         {
9998                 int l, k;
9999                 vec3_t v;
10000                 if (r_showdisabledepthtest.integer)
10001                 {
10002                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10003                         GL_DepthMask(false);
10004                 }
10005                 else
10006                 {
10007                         GL_BlendFunc(GL_ONE, GL_ZERO);
10008                         GL_DepthMask(true);
10009                 }
10010                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10011                 {
10012                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10013                                 continue;
10014                         rsurface.texture = R_GetCurrentTexture(surface->texture);
10015                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10016                         {
10017                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
10018                                 qglBegin(GL_LINES);
10019                                 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
10020                                 {
10021                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10022                                         {
10023                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10024                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10025                                                 qglVertex3f(v[0], v[1], v[2]);
10026                                                 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10027                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10028                                                 qglVertex3f(v[0], v[1], v[2]);
10029                                         }
10030                                 }
10031                                 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
10032                                 {
10033                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10034                                         {
10035                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10036                                                 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
10037                                                 qglVertex3f(v[0], v[1], v[2]);
10038                                                 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
10039                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10040                                                 qglVertex3f(v[0], v[1], v[2]);
10041                                         }
10042                                 }
10043                                 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
10044                                 {
10045                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10046                                         {
10047                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10048                                                 GL_Color(0, r_refdef.view.colorscale, 0, 1);
10049                                                 qglVertex3f(v[0], v[1], v[2]);
10050                                                 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
10051                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10052                                                 qglVertex3f(v[0], v[1], v[2]);
10053                                         }
10054                                 }
10055                                 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
10056                                 {
10057                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10058                                         {
10059                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10060                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10061                                                 qglVertex3f(v[0], v[1], v[2]);
10062                                                 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10063                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10064                                                 qglVertex3f(v[0], v[1], v[2]);
10065                                         }
10066                                 }
10067                                 qglEnd();
10068                                 CHECKGLERROR
10069                         }
10070                 }
10071                 rsurface.texture = NULL;
10072         }
10073 # endif
10074 #endif
10075 }
10076
10077 int r_maxsurfacelist = 0;
10078 const msurface_t **r_surfacelist = NULL;
10079 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass)
10080 {
10081         int i, j, endj, flagsmask;
10082         dp_model_t *model = ent->model;
10083         msurface_t *surfaces;
10084         unsigned char *update;
10085         int numsurfacelist = 0;
10086         if (model == NULL)
10087                 return;
10088
10089         if (r_maxsurfacelist < model->num_surfaces)
10090         {
10091                 r_maxsurfacelist = model->num_surfaces;
10092                 if (r_surfacelist)
10093                         Mem_Free((msurface_t **)r_surfacelist);
10094                 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
10095         }
10096
10097         if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
10098                 RSurf_ActiveModelEntity(ent, false, false, false);
10099         else if (prepass)
10100                 RSurf_ActiveModelEntity(ent, true, true, true);
10101         else if (depthonly)
10102                 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
10103         else
10104                 RSurf_ActiveModelEntity(ent, true, true, false);
10105
10106         surfaces = model->data_surfaces;
10107         update = model->brushq1.lightmapupdateflags;
10108
10109         // update light styles
10110         if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0)
10111         {
10112                 model_brush_lightstyleinfo_t *style;
10113                 for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
10114                 {
10115                         if (style->value != r_refdef.scene.lightstylevalue[style->style])
10116                         {
10117                                 int *list = style->surfacelist;
10118                                 style->value = r_refdef.scene.lightstylevalue[style->style];
10119                                 for (j = 0;j < style->numsurfaces;j++)
10120                                         update[list[j]] = true;
10121                         }
10122                 }
10123         }
10124
10125         flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
10126
10127         if (debug)
10128         {
10129                 R_DrawDebugModel();
10130                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10131                 return;
10132         }
10133
10134         rsurface.lightmaptexture = NULL;
10135         rsurface.deluxemaptexture = NULL;
10136         rsurface.uselightmaptexture = false;
10137         rsurface.texture = NULL;
10138         rsurface.rtlight = NULL;
10139         numsurfacelist = 0;
10140         // add visible surfaces to draw list
10141         if (ent == r_refdef.scene.worldentity)
10142         {
10143                 // for the world entity, check surfacevisible
10144                 for (i = 0;i < model->nummodelsurfaces;i++)
10145                 {
10146                         j = model->sortedmodelsurfaces[i];
10147                         if (r_refdef.viewcache.world_surfacevisible[j])
10148                                 r_surfacelist[numsurfacelist++] = surfaces + j;
10149                 }
10150         }
10151         else
10152         {
10153                 // add all surfaces
10154                 for (i = 0; i < model->nummodelsurfaces; i++)
10155                         r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
10156         }
10157         // don't do anything if there were no surfaces
10158         if (!numsurfacelist)
10159         {
10160                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10161                 return;
10162         }
10163         // update lightmaps if needed
10164         if (update)
10165         {
10166                 int updated = 0;
10167                 for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
10168                 {
10169                         if (update[j])
10170                         {
10171                                 updated++;
10172                                 R_BuildLightMap(ent, surfaces + j);
10173                         }
10174                 }
10175         }
10176
10177         R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass);
10178
10179         // add to stats if desired
10180         if (r_speeds.integer && !skysurfaces && !depthonly)
10181         {
10182                 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10183                 for (j = 0;j < numsurfacelist;j++)
10184                         r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10185         }
10186
10187         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10188 }
10189
10190 void R_DebugLine(vec3_t start, vec3_t end)
10191 {
10192         dp_model_t *mod = CL_Mesh_UI();
10193         msurface_t *surf;
10194         int e0, e1, e2, e3;
10195         float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10196         float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10197         float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10198         vec4_t w[2], s[2];
10199
10200         // transform to screen coords first
10201         Vector4Set(w[0], start[0], start[1], start[2], 1);
10202         Vector4Set(w[1], end[0], end[1], end[2], 1);
10203         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10204         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10205         x1 = s[0][0] * vid_conwidth.value / vid.width;
10206         y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10207         x2 = s[1][0] * vid_conwidth.value / vid.width;
10208         y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10209         //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10210
10211         // add the line to the UI mesh for drawing later
10212
10213         // width is measured in real pixels
10214         if (fabs(x2 - x1) > fabs(y2 - y1))
10215         {
10216                 offsetx = 0;
10217                 offsety = 0.5f * width * vid_conheight.value / vid.height;
10218         }
10219         else
10220         {
10221                 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10222                 offsety = 0;
10223         }
10224         surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_VERTEXCOLOR), true);
10225         e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10226         e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10227         e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10228         e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10229         Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10230         Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10231
10232 }
10233
10234
10235 void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass)
10236 {
10237         int q;
10238         static texture_t texture;
10239         static msurface_t surface;
10240         const msurface_t *surfacelist = &surface;
10241
10242         // fake enough texture and surface state to render this geometry
10243
10244         texture.update_lastrenderframe = -1; // regenerate this texture
10245         texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10246         texture.basealpha = 1.0f;
10247         texture.currentskinframe = skinframe;
10248         texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10249         texture.offsetmapping = OFFSETMAPPING_OFF;
10250         texture.offsetscale = 1;
10251         texture.specularscalemod = 1;
10252         texture.specularpowermod = 1;
10253         texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10254         // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
10255         // JUST GREP FOR "specularscalemod = 1".
10256
10257         for (q = 0; q < 3; q++)
10258         {
10259                 texture.render_glowmod[q] = r_refdef.view.colorscale * r_hdr_glowintensity.value;
10260                 texture.render_modellight_lightdir[q] = q == 2;
10261                 texture.render_modellight_ambient[q] = r_refdef.view.colorscale * r_refdef.scene.ambientintensity;
10262                 texture.render_modellight_diffuse[q] = r_refdef.view.colorscale;
10263                 texture.render_modellight_specular[q] = r_refdef.view.colorscale;
10264                 texture.render_lightmap_ambient[q] = r_refdef.view.colorscale * r_refdef.scene.ambientintensity;
10265                 texture.render_lightmap_diffuse[q] = r_refdef.view.colorscale * r_refdef.scene.lightmapintensity;
10266                 texture.render_lightmap_specular[q] = r_refdef.view.colorscale;
10267                 texture.render_rtlight_diffuse[q] = r_refdef.view.colorscale;
10268                 texture.render_rtlight_specular[q] = r_refdef.view.colorscale;
10269         }
10270         texture.currentalpha = 1.0f;
10271
10272         surface.texture = &texture;
10273         surface.num_triangles = numtriangles;
10274         surface.num_firsttriangle = firsttriangle;
10275         surface.num_vertices = numvertices;
10276         surface.num_firstvertex = firstvertex;
10277
10278         // now render it
10279         rsurface.texture = R_GetCurrentTexture(surface.texture);
10280         rsurface.lightmaptexture = NULL;
10281         rsurface.deluxemaptexture = NULL;
10282         rsurface.uselightmaptexture = false;
10283         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);
10284 }
10285
10286 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)
10287 {
10288         static msurface_t surface;
10289         const msurface_t *surfacelist = &surface;
10290
10291         // fake enough texture and surface state to render this geometry
10292         surface.texture = texture;
10293         surface.num_triangles = numtriangles;
10294         surface.num_firsttriangle = firsttriangle;
10295         surface.num_vertices = numvertices;
10296         surface.num_firstvertex = firstvertex;
10297
10298         // now render it
10299         rsurface.texture = R_GetCurrentTexture(surface.texture);
10300         rsurface.lightmaptexture = NULL;
10301         rsurface.deluxemaptexture = NULL;
10302         rsurface.uselightmaptexture = false;
10303         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);
10304 }