]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
Added lightgrid texture based lighting in q3bsp maps by uploading it as a 3D texture...
[xonotic/darkplaces.git] / gl_rmain.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_main.c
21
22 #include "quakedef.h"
23 #include "r_shadow.h"
24 #include "polygon.h"
25 #include "image.h"
26 #include "ft2.h"
27 #include "csprogs.h"
28 #include "cl_video.h"
29 #include "cl_collision.h"
30
31 #ifdef WIN32
32 // Enable NVIDIA High Performance Graphics while using Integrated Graphics.
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36 __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
37 #ifdef __cplusplus
38 }
39 #endif
40 #endif
41
42 mempool_t *r_main_mempool;
43 rtexturepool_t *r_main_texturepool;
44
45 int r_textureframe = 0; ///< used only by R_GetCurrentTexture, incremented per view and per UI render
46
47 static qboolean r_loadnormalmap;
48 static qboolean r_loadgloss;
49 qboolean r_loadfog;
50 static qboolean r_loaddds;
51 static qboolean r_savedds;
52 static qboolean r_gpuskeletal;
53
54 //
55 // screen size info
56 //
57 r_refdef_t r_refdef;
58
59 cvar_t r_motionblur = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur", "0", "screen motionblur - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
60 cvar_t r_damageblur = {CVAR_CLIENT | CVAR_SAVE, "r_damageblur", "0", "screen motionblur based on damage - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
61 cvar_t r_motionblur_averaging = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_averaging", "0.1", "sliding average reaction time for velocity (higher = slower adaption to change)"};
62 cvar_t r_motionblur_randomize = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"};
63 cvar_t r_motionblur_minblur = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_minblur", "0.5", "factor of blur to apply at all times (always have this amount of blur no matter what the other factors are)"};
64 cvar_t r_motionblur_maxblur = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_maxblur", "0.9", "maxmimum amount of blur"};
65 cvar_t r_motionblur_velocityfactor = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_velocityfactor", "1", "factoring in of player velocity to the blur equation - the faster the player moves around the map, the more blur they get"};
66 cvar_t r_motionblur_velocityfactor_minspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_velocityfactor_minspeed", "400", "lower value of velocity when it starts to factor into blur equation"};
67 cvar_t r_motionblur_velocityfactor_maxspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_velocityfactor_maxspeed", "800", "upper value of velocity when it reaches the peak factor into blur equation"};
68 cvar_t r_motionblur_mousefactor = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_mousefactor", "2", "factoring in of mouse acceleration to the blur equation - the faster the player turns their mouse, the more blur they get"};
69 cvar_t r_motionblur_mousefactor_minspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_mousefactor_minspeed", "0", "lower value of mouse acceleration when it starts to factor into blur equation"};
70 cvar_t r_motionblur_mousefactor_maxspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_mousefactor_maxspeed", "50", "upper value of mouse acceleration when it reaches the peak factor into blur equation"};
71
72 cvar_t r_depthfirst = {CVAR_CLIENT | CVAR_SAVE, "r_depthfirst", "0", "renders a depth-only version of the scene before normal rendering begins to eliminate overdraw, values: 0 = off, 1 = world depth, 2 = world and model depth"};
73 cvar_t r_useinfinitefarclip = {CVAR_CLIENT | CVAR_SAVE, "r_useinfinitefarclip", "1", "enables use of a special kind of projection matrix that has an extremely large farclip"};
74 cvar_t r_farclip_base = {CVAR_CLIENT, "r_farclip_base", "65536", "farclip (furthest visible distance) for rendering when r_useinfinitefarclip is 0"};
75 cvar_t r_farclip_world = {CVAR_CLIENT, "r_farclip_world", "2", "adds map size to farclip multiplied by this value"};
76 cvar_t r_nearclip = {CVAR_CLIENT, "r_nearclip", "1", "distance from camera of nearclip plane" };
77 cvar_t r_deformvertexes = {CVAR_CLIENT, "r_deformvertexes", "1", "allows use of deformvertexes in shader files (can be turned off to check performance impact)"};
78 cvar_t r_transparent = {CVAR_CLIENT, "r_transparent", "1", "allows use of transparent surfaces (can be turned off to check performance impact)"};
79 cvar_t r_transparent_alphatocoverage = {CVAR_CLIENT, "r_transparent_alphatocoverage", "1", "enables GL_ALPHA_TO_COVERAGE antialiasing technique on alphablend and alphatest surfaces when using vid_samples 2 or higher"};
80 cvar_t r_transparent_sortsurfacesbynearest = {CVAR_CLIENT, "r_transparent_sortsurfacesbynearest", "1", "sort entity and world surfaces by nearest point on bounding box instead of using the center of the bounding box, usually reduces sorting artifacts"};
81 cvar_t r_transparent_useplanardistance = {CVAR_CLIENT, "r_transparent_useplanardistance", "0", "sort transparent meshes by distance from view plane rather than spherical distance to the chosen point"};
82 cvar_t r_showoverdraw = {CVAR_CLIENT, "r_showoverdraw", "0", "shows overlapping geometry"};
83 cvar_t r_showbboxes = {CVAR_CLIENT, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
84 cvar_t r_showbboxes_client = {CVAR_CLIENT, "r_showbboxes_client", "0", "shows bounding boxes of clientside qc entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
85 cvar_t r_showsurfaces = {CVAR_CLIENT, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 2 shows triangle draw order (for analyzing whether meshes are optimized for vertex cache)"};
86 cvar_t r_showtris = {CVAR_CLIENT, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
87 cvar_t r_shownormals = {CVAR_CLIENT, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
88 cvar_t r_showlighting = {CVAR_CLIENT, "r_showlighting", "0", "shows areas lit by lights, useful for finding out why some areas of a map render slowly (bright orange = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
89 cvar_t r_showcollisionbrushes = {CVAR_CLIENT, "r_showcollisionbrushes", "0", "draws collision brushes in quake3 maps (mode 1), mode 2 disables rendering of world (trippy!)"};
90 cvar_t r_showcollisionbrushes_polygonfactor = {CVAR_CLIENT, "r_showcollisionbrushes_polygonfactor", "-1", "expands outward the brush polygons a little bit, used to make collision brushes appear infront of walls"};
91 cvar_t r_showcollisionbrushes_polygonoffset = {CVAR_CLIENT, "r_showcollisionbrushes_polygonoffset", "0", "nudges brush polygon depth in hardware depth units, used to make collision brushes appear infront of walls"};
92 cvar_t r_showdisabledepthtest = {CVAR_CLIENT, "r_showdisabledepthtest", "0", "disables depth testing on r_show* cvars, allowing you to see what hidden geometry the graphics card is processing"};
93 cvar_t r_showspriteedges = {CVAR_CLIENT, "r_showspriteedges", "0", "renders a debug outline to show the polygon shape of each sprite frame rendered (may be 2 or more in case of interpolated animations), for debugging rendering bugs with specific view types"};
94 cvar_t r_showparticleedges = {CVAR_CLIENT, "r_showparticleedges", "0", "renders a debug outline to show the polygon shape of each particle, for debugging rendering bugs with specific view types"};
95 cvar_t r_drawportals = {CVAR_CLIENT, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
96 cvar_t r_drawentities = {CVAR_CLIENT, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
97 cvar_t r_draw2d = {CVAR_CLIENT, "r_draw2d","1", "draw 2D stuff (dangerous to turn off)"};
98 cvar_t r_drawworld = {CVAR_CLIENT, "r_drawworld","1", "draw world (most static stuff)"};
99 cvar_t r_drawviewmodel = {CVAR_CLIENT, "r_drawviewmodel","1", "draw your weapon model"};
100 cvar_t r_drawexteriormodel = {CVAR_CLIENT, "r_drawexteriormodel","1", "draw your player model (e.g. in chase cam, reflections)"};
101 cvar_t r_cullentities_trace = {CVAR_CLIENT, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
102 cvar_t r_cullentities_trace_entityocclusion = {CVAR_CLIENT, "r_cullentities_trace_entityocclusion", "1", "check for occluding entities such as doors, not just world hull"};
103 cvar_t r_cullentities_trace_samples = {CVAR_CLIENT, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling (in addition to center sample)"};
104 cvar_t r_cullentities_trace_tempentitysamples = {CVAR_CLIENT, "r_cullentities_trace_tempentitysamples", "-1", "number of samples to test for entity culling of temp entities (including all CSQC entities), -1 disables trace culling on these entities to prevent flicker (pvs still applies)"};
105 cvar_t r_cullentities_trace_enlarge = {CVAR_CLIENT, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
106 cvar_t r_cullentities_trace_expand = {CVAR_CLIENT, "r_cullentities_trace_expand", "0", "box expanded by this many units for entity culling"};
107 cvar_t r_cullentities_trace_pad = {CVAR_CLIENT, "r_cullentities_trace_pad", "8", "accept traces that hit within this many units of the box"};
108 cvar_t r_cullentities_trace_delay = {CVAR_CLIENT, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
109 cvar_t r_cullentities_trace_eyejitter = {CVAR_CLIENT, "r_cullentities_trace_eyejitter", "16", "randomly offset rays from the eye by this much to reduce the odds of flickering"};
110 cvar_t r_sortentities = {CVAR_CLIENT, "r_sortentities", "0", "sort entities before drawing (might be faster)"};
111 cvar_t r_speeds = {CVAR_CLIENT, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
112 cvar_t r_fullbright = {CVAR_CLIENT, "r_fullbright","0", "makes map very bright and renders faster"};
113
114 cvar_t r_fullbright_directed = {CVAR_CLIENT, "r_fullbright_directed", "0", "render fullbright things (unlit worldmodel and EF_FULLBRIGHT entities, but not fullbright shaders) using a constant light direction instead to add more depth while keeping uniform brightness"};
115 cvar_t r_fullbright_directed_ambient = {CVAR_CLIENT, "r_fullbright_directed_ambient", "0.5", "ambient light multiplier for directed fullbright"};
116 cvar_t r_fullbright_directed_diffuse = {CVAR_CLIENT, "r_fullbright_directed_diffuse", "0.75", "diffuse light multiplier for directed fullbright"};
117 cvar_t r_fullbright_directed_pitch = {CVAR_CLIENT, "r_fullbright_directed_pitch", "20", "constant pitch direction ('height') of the fake light source to use for fullbright"};
118 cvar_t r_fullbright_directed_pitch_relative = {CVAR_CLIENT, "r_fullbright_directed_pitch_relative", "0", "whether r_fullbright_directed_pitch is interpreted as absolute (0) or relative (1) pitch"};
119
120 cvar_t r_wateralpha = {CVAR_CLIENT | CVAR_SAVE, "r_wateralpha","1", "opacity of water polygons"};
121 cvar_t r_dynamic = {CVAR_CLIENT | CVAR_SAVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
122 cvar_t r_fullbrights = {CVAR_CLIENT | CVAR_SAVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
123 cvar_t r_shadows = {CVAR_CLIENT | CVAR_SAVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this); when set to 2, always cast the shadows in the direction set by r_shadows_throwdirection, otherwise use the model lighting."};
124 cvar_t r_shadows_darken = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_darken", "0.5", "how much shadowed areas will be darkened"};
125 cvar_t r_shadows_throwdistance = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
126 cvar_t r_shadows_throwdirection = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_throwdirection", "0 0 -1", "override throwing direction for r_shadows 2"};
127 cvar_t r_shadows_drawafterrtlighting = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_drawafterrtlighting", "0", "draw fake shadows AFTER realtime lightning is drawn. May be useful for simulating fast sunlight on large outdoor maps with only one noshadow rtlight. The price is less realistic appearance of dynamic light shadows."};
128 cvar_t r_shadows_castfrombmodels = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
129 cvar_t r_shadows_focus = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_focus", "0 0 0", "offset the shadowed area focus"};
130 cvar_t r_shadows_shadowmapscale = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_shadowmapscale", "0.25", "higher values increase shadowmap quality at a cost of area covered (multiply global shadowmap precision) for fake shadows. Needs shadowmapping ON."};
131 cvar_t r_shadows_shadowmapbias = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_shadowmapbias", "-1", "sets shadowmap bias for fake shadows. -1 sets the value of r_shadow_shadowmapping_bias. Needs shadowmapping ON."};
132 cvar_t r_q1bsp_skymasking = {CVAR_CLIENT, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
133 cvar_t r_polygonoffset_submodel_factor = {CVAR_CLIENT, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
134 cvar_t r_polygonoffset_submodel_offset = {CVAR_CLIENT, "r_polygonoffset_submodel_offset", "14", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
135 cvar_t r_polygonoffset_decals_factor = {CVAR_CLIENT, "r_polygonoffset_decals_factor", "0", "biases depth values of decals to prevent z-fighting artifacts"};
136 cvar_t r_polygonoffset_decals_offset = {CVAR_CLIENT, "r_polygonoffset_decals_offset", "-14", "biases depth values of decals to prevent z-fighting artifacts"};
137 cvar_t r_fog_exp2 = {CVAR_CLIENT, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"};
138 cvar_t r_fog_clear = {CVAR_CLIENT, "r_fog_clear", "1", "clears renderbuffer with fog color before render starts"};
139 cvar_t r_drawfog = {CVAR_CLIENT | CVAR_SAVE, "r_drawfog", "1", "allows one to disable fog rendering"};
140 cvar_t r_transparentdepthmasking = {CVAR_CLIENT | CVAR_SAVE, "r_transparentdepthmasking", "0", "enables depth writes on transparent meshes whose materially is normally opaque, this prevents seeing the inside of a transparent mesh"};
141 cvar_t r_transparent_sortmindist = {CVAR_CLIENT | CVAR_SAVE, "r_transparent_sortmindist", "0", "lower distance limit for transparent sorting"};
142 cvar_t r_transparent_sortmaxdist = {CVAR_CLIENT | CVAR_SAVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"};
143 cvar_t r_transparent_sortarraysize = {CVAR_CLIENT | CVAR_SAVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"};
144 cvar_t r_celshading = {CVAR_CLIENT | CVAR_SAVE, "r_celshading", "0", "cartoon-style light shading (OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9
145 cvar_t r_celoutlines = {CVAR_CLIENT | CVAR_SAVE, "r_celoutlines", "0", "cartoon-style outlines (requires r_shadow_deferred)"};
146
147 cvar_t gl_fogenable = {CVAR_CLIENT, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
148 cvar_t gl_fogdensity = {CVAR_CLIENT, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
149 cvar_t gl_fogred = {CVAR_CLIENT, "gl_fogred","0.3", "nehahra fog color red value (for Nehahra compatibility only)"};
150 cvar_t gl_foggreen = {CVAR_CLIENT, "gl_foggreen","0.3", "nehahra fog color green value (for Nehahra compatibility only)"};
151 cvar_t gl_fogblue = {CVAR_CLIENT, "gl_fogblue","0.3", "nehahra fog color blue value (for Nehahra compatibility only)"};
152 cvar_t gl_fogstart = {CVAR_CLIENT, "gl_fogstart", "0", "nehahra fog start distance (for Nehahra compatibility only)"};
153 cvar_t gl_fogend = {CVAR_CLIENT, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
154 cvar_t gl_skyclip = {CVAR_CLIENT, "gl_skyclip", "4608", "nehahra farclip distance - the real fog end (for Nehahra compatibility only)"};
155
156 cvar_t r_texture_dds_load = {CVAR_CLIENT | CVAR_SAVE, "r_texture_dds_load", "0", "load compressed dds/filename.dds texture instead of filename.tga, if the file exists (requires driver support)"};
157 cvar_t r_texture_dds_save = {CVAR_CLIENT | CVAR_SAVE, "r_texture_dds_save", "0", "save compressed dds/filename.dds texture when filename.tga is loaded, so that it can be loaded instead next time"};
158
159 cvar_t r_textureunits = {CVAR_CLIENT, "r_textureunits", "32", "number of texture units to use in GL 1.1 and GL 1.3 rendering paths"};
160 static cvar_t gl_combine = {CVAR_CLIENT | CVAR_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"};
161 static cvar_t r_glsl = {CVAR_CLIENT | CVAR_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"};
162
163 cvar_t r_usedepthtextures = {CVAR_CLIENT | CVAR_SAVE, "r_usedepthtextures", "1", "use depth texture instead of depth renderbuffer where possible, uses less video memory but may render slower (or faster) depending on hardware"};
164 cvar_t r_viewfbo = {CVAR_CLIENT | CVAR_SAVE, "r_viewfbo", "0", "enables use of an 8bit (1) or 16bit (2) or 32bit (3) per component float framebuffer render, which may be at a different resolution than the video mode"};
165 cvar_t r_rendertarget_debug = {CVAR_CLIENT, "r_rendertarget_debug", "-1", "replaces the view with the contents of the specified render target (by number - note that these can fluctuate depending on scene)"};
166 cvar_t r_viewscale = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale", "1", "scaling factor for resolution of the fbo rendering method, must be > 0, can be above 1 for a costly antialiasing behavior, typical values are 0.5 for 1/4th as many pixels rendered, or 1 for normal rendering"};
167 cvar_t r_viewscale_fpsscaling = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling", "0", "change resolution based on framerate"};
168 cvar_t r_viewscale_fpsscaling_min = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_min", "0.0625", "worst acceptable quality"};
169 cvar_t r_viewscale_fpsscaling_multiply = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_multiply", "5", "adjust quality up or down by the frametime difference from 1.0/target, multiplied by this factor"};
170 cvar_t r_viewscale_fpsscaling_stepsize = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_stepsize", "0.01", "smallest adjustment to hit the target framerate (this value prevents minute oscillations)"};
171 cvar_t r_viewscale_fpsscaling_stepmax = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_stepmax", "1.00", "largest adjustment to hit the target framerate (this value prevents wild overshooting of the estimate)"};
172 cvar_t r_viewscale_fpsscaling_target = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_target", "70", "desired framerate"};
173
174 cvar_t r_glsl_skeletal = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_skeletal", "1", "render skeletal models faster using a gpu-skinning technique"};
175 cvar_t r_glsl_deluxemapping = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
176 cvar_t r_glsl_offsetmapping = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
177 cvar_t r_glsl_offsetmapping_steps = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_steps", "2", "offset mapping steps (note: too high values may be not supported by your GPU)"};
178 cvar_t r_glsl_offsetmapping_reliefmapping = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
179 cvar_t r_glsl_offsetmapping_reliefmapping_steps = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_steps", "10", "relief mapping steps (note: too high values may be not supported by your GPU)"};
180 cvar_t r_glsl_offsetmapping_reliefmapping_refinesteps = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_refinesteps", "5", "relief mapping refine steps (these are a binary search executed as the last step as given by r_glsl_offsetmapping_reliefmapping_steps)"};
181 cvar_t r_glsl_offsetmapping_scale = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
182 cvar_t r_glsl_offsetmapping_lod = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_lod", "0", "apply distance-based level-of-detail correction to number of offsetmappig steps, effectively making it render faster on large open-area maps"};
183 cvar_t r_glsl_offsetmapping_lod_distance = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_lod_distance", "32", "first LOD level distance, second level (-50% steps) is 2x of this, third (33%) - 3x etc."};
184 cvar_t r_glsl_postprocess = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess", "0", "use a GLSL postprocessing shader"};
185 cvar_t r_glsl_postprocess_uservec1 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec1", "0 0 0 0", "a 4-component vector to pass as uservec1 to the postprocessing shader (only useful if default.glsl has been customized)"};
186 cvar_t r_glsl_postprocess_uservec2 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec2", "0 0 0 0", "a 4-component vector to pass as uservec2 to the postprocessing shader (only useful if default.glsl has been customized)"};
187 cvar_t r_glsl_postprocess_uservec3 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec3", "0 0 0 0", "a 4-component vector to pass as uservec3 to the postprocessing shader (only useful if default.glsl has been customized)"};
188 cvar_t r_glsl_postprocess_uservec4 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec4", "0 0 0 0", "a 4-component vector to pass as uservec4 to the postprocessing shader (only useful if default.glsl has been customized)"};
189 cvar_t r_glsl_postprocess_uservec1_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec1_enable", "1", "enables postprocessing uservec1 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
190 cvar_t r_glsl_postprocess_uservec2_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec2_enable", "1", "enables postprocessing uservec2 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
191 cvar_t r_glsl_postprocess_uservec3_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec3_enable", "1", "enables postprocessing uservec3 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
192 cvar_t r_glsl_postprocess_uservec4_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec4_enable", "1", "enables postprocessing uservec4 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
193 cvar_t r_colorfringe = {CVAR_CLIENT | CVAR_SAVE, "r_colorfringe", "0", "Chromatic aberration. Values higher than 0.025 will noticeably distort the image"};
194
195 cvar_t r_water = {CVAR_CLIENT | CVAR_SAVE, "r_water", "0", "whether to use reflections and refraction on water surfaces (note: r_wateralpha must be set below 1)"};
196 cvar_t r_water_cameraentitiesonly = {CVAR_CLIENT | CVAR_SAVE, "r_water_cameraentitiesonly", "0", "whether to only show QC-defined reflections/refractions (typically used for camera- or portal-like effects)"};
197 cvar_t r_water_clippingplanebias = {CVAR_CLIENT | CVAR_SAVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
198 cvar_t r_water_resolutionmultiplier = {CVAR_CLIENT | CVAR_SAVE, "r_water_resolutionmultiplier", "0.5", "multiplier for screen resolution when rendering refracted/reflected scenes, 1 is full quality, lower values are faster"};
199 cvar_t r_water_refractdistort = {CVAR_CLIENT | CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
200 cvar_t r_water_reflectdistort = {CVAR_CLIENT | CVAR_SAVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
201 cvar_t r_water_scissormode = {CVAR_CLIENT, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
202 cvar_t r_water_lowquality = {CVAR_CLIENT, "r_water_lowquality", "0", "special option to accelerate water rendering: 1 disables all dynamic lights, 2 disables particles too"};
203 cvar_t r_water_hideplayer = {CVAR_CLIENT | CVAR_SAVE, "r_water_hideplayer", "0", "if set to 1 then player will be hidden in refraction views, if set to 2 then player will also be hidden in reflection views, player is always visible in camera views"};
204
205 cvar_t r_lerpsprites = {CVAR_CLIENT | CVAR_SAVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"};
206 cvar_t r_lerpmodels = {CVAR_CLIENT | CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
207 cvar_t r_lerplightstyles = {CVAR_CLIENT | CVAR_SAVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
208 cvar_t r_waterscroll = {CVAR_CLIENT | CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
209
210 cvar_t r_bloom = {CVAR_CLIENT | CVAR_SAVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
211 cvar_t r_bloom_colorscale = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorscale", "1", "how bright the glow is"};
212
213 cvar_t r_bloom_brighten = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_brighten", "2", "how bright the glow is, after subtract/power"};
214 cvar_t r_bloom_blur = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_blur", "4", "how large the glow is"};
215 cvar_t r_bloom_resolution = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
216 cvar_t r_bloom_colorexponent = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorexponent", "1", "how exaggerated the glow is"};
217 cvar_t r_bloom_colorsubtract = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorsubtract", "0.125", "reduces bloom colors by a certain amount"};
218 cvar_t r_bloom_scenebrightness = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_scenebrightness", "1", "global rendering brightness when bloom is enabled"};
219
220 cvar_t r_hdr_scenebrightness = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
221 cvar_t r_hdr_glowintensity = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
222 cvar_t r_hdr_irisadaptation = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation", "0", "adjust scene brightness according to light intensity at player location"};
223 cvar_t r_hdr_irisadaptation_multiplier = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_multiplier", "2", "brightness at which value will be 1.0"};
224 cvar_t r_hdr_irisadaptation_minvalue = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_minvalue", "0.5", "minimum value that can result from multiplier / brightness"};
225 cvar_t r_hdr_irisadaptation_maxvalue = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_maxvalue", "4", "maximum value that can result from multiplier / brightness"};
226 cvar_t r_hdr_irisadaptation_value = {CVAR_CLIENT, "r_hdr_irisadaptation_value", "1", "current value as scenebrightness multiplier, changes continuously when irisadaptation is active"};
227 cvar_t r_hdr_irisadaptation_fade_up = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_fade_up", "0.1", "fade rate at which value adjusts to darkness"};
228 cvar_t r_hdr_irisadaptation_fade_down = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_fade_down", "0.5", "fade rate at which value adjusts to brightness"};
229 cvar_t r_hdr_irisadaptation_radius = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_radius", "15", "lighting within this many units of the eye is averaged"};
230
231 cvar_t r_smoothnormals_areaweighting = {CVAR_CLIENT, "r_smoothnormals_areaweighting", "1", "uses significantly faster (and supposedly higher quality) area-weighted vertex normals and tangent vectors rather than summing normalized triangle normals and tangents"};
232
233 cvar_t developer_texturelogging = {CVAR_CLIENT, "developer_texturelogging", "0", "produces a textures.log file containing names of skins and map textures the engine tried to load"};
234
235 cvar_t gl_lightmaps = {CVAR_CLIENT, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers), a value of 2 keeps normalmap shading"};
236
237 cvar_t r_test = {CVAR_CLIENT, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
238
239 cvar_t r_batch_multidraw = {CVAR_CLIENT | CVAR_SAVE, "r_batch_multidraw", "1", "issue multiple glDrawElements calls when rendering a batch of surfaces with the same texture (otherwise the index data is copied to make it one draw)"};
240 cvar_t r_batch_multidraw_mintriangles = {CVAR_CLIENT | CVAR_SAVE, "r_batch_multidraw_mintriangles", "0", "minimum number of triangles to activate multidraw path (copying small groups of triangles may be faster)"};
241 cvar_t r_batch_debugdynamicvertexpath = {CVAR_CLIENT | CVAR_SAVE, "r_batch_debugdynamicvertexpath", "0", "force the dynamic batching code path for debugging purposes"};
242 cvar_t r_batch_dynamicbuffer = {CVAR_CLIENT | CVAR_SAVE, "r_batch_dynamicbuffer", "0", "use vertex/index buffers for drawing dynamic and copytriangles batches"};
243
244 cvar_t r_glsl_saturation = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
245 cvar_t r_glsl_saturation_redcompensate = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_saturation_redcompensate", "0", "a 'vampire sight' addition to desaturation effect, does compensation for red color, r_glsl_restart is required"};
246
247 cvar_t r_glsl_vertextextureblend_usebothalphas = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_vertextextureblend_usebothalphas", "0", "use both alpha layers on vertex blended surfaces, each alpha layer sets amount of 'blend leak' on another layer, requires mod_q3shader_force_terrain_alphaflag on."};
248
249 cvar_t r_framedatasize = {CVAR_CLIENT | CVAR_SAVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"};
250 cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
251 {
252         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"},
253         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"},
254         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"},
255         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
256 };
257
258 extern cvar_t v_glslgamma_2d;
259
260 extern qboolean v_flipped_state;
261
262 r_framebufferstate_t r_fb;
263
264 /// shadow volume bsp struct with automatically growing nodes buffer
265 svbsp_t r_svbsp;
266
267 int r_uniformbufferalignment = 32; // dynamically updated to match GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
268
269 rtexture_t *r_texture_blanknormalmap;
270 rtexture_t *r_texture_white;
271 rtexture_t *r_texture_grey128;
272 rtexture_t *r_texture_black;
273 rtexture_t *r_texture_notexture;
274 rtexture_t *r_texture_whitecube;
275 rtexture_t *r_texture_normalizationcube;
276 rtexture_t *r_texture_fogattenuation;
277 rtexture_t *r_texture_fogheighttexture;
278 rtexture_t *r_texture_gammaramps;
279 unsigned int r_texture_gammaramps_serial;
280 //rtexture_t *r_texture_fogintensity;
281 rtexture_t *r_texture_reflectcube;
282
283 // TODO: hash lookups?
284 typedef struct cubemapinfo_s
285 {
286         char basename[64];
287         rtexture_t *texture;
288 }
289 cubemapinfo_t;
290
291 int r_texture_numcubemaps;
292 cubemapinfo_t *r_texture_cubemaps[MAX_CUBEMAPS];
293
294 unsigned int r_queries[MAX_OCCLUSION_QUERIES];
295 unsigned int r_numqueries;
296 unsigned int r_maxqueries;
297
298 typedef struct r_qwskincache_s
299 {
300         char name[MAX_QPATH];
301         skinframe_t *skinframe;
302 }
303 r_qwskincache_t;
304
305 static r_qwskincache_t *r_qwskincache;
306 static int r_qwskincache_size;
307
308 /// vertex coordinates for a quad that covers the screen exactly
309 extern const float r_screenvertex3f[12];
310 const float r_screenvertex3f[12] =
311 {
312         0, 0, 0,
313         1, 0, 0,
314         1, 1, 0,
315         0, 1, 0
316 };
317
318 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
319 {
320         int i;
321         for (i = 0;i < verts;i++)
322         {
323                 out[0] = in[0] * r;
324                 out[1] = in[1] * g;
325                 out[2] = in[2] * b;
326                 out[3] = in[3];
327                 in += 4;
328                 out += 4;
329         }
330 }
331
332 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
333 {
334         int i;
335         for (i = 0;i < verts;i++)
336         {
337                 out[0] = r;
338                 out[1] = g;
339                 out[2] = b;
340                 out[3] = a;
341                 out += 4;
342         }
343 }
344
345 // FIXME: move this to client?
346 void FOG_clear(void)
347 {
348         if (gamemode == GAME_NEHAHRA)
349         {
350                 Cvar_Set(&cvars_all, "gl_fogenable", "0");
351                 Cvar_Set(&cvars_all, "gl_fogdensity", "0.2");
352                 Cvar_Set(&cvars_all, "gl_fogred", "0.3");
353                 Cvar_Set(&cvars_all, "gl_foggreen", "0.3");
354                 Cvar_Set(&cvars_all, "gl_fogblue", "0.3");
355         }
356         r_refdef.fog_density = 0;
357         r_refdef.fog_red = 0;
358         r_refdef.fog_green = 0;
359         r_refdef.fog_blue = 0;
360         r_refdef.fog_alpha = 1;
361         r_refdef.fog_start = 0;
362         r_refdef.fog_end = 16384;
363         r_refdef.fog_height = 1<<30;
364         r_refdef.fog_fadedepth = 128;
365         memset(r_refdef.fog_height_texturename, 0, sizeof(r_refdef.fog_height_texturename));
366 }
367
368 static void R_BuildBlankTextures(void)
369 {
370         unsigned char data[4];
371         data[2] = 128; // normal X
372         data[1] = 128; // normal Y
373         data[0] = 255; // normal Z
374         data[3] = 255; // height
375         r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
376         data[0] = 255;
377         data[1] = 255;
378         data[2] = 255;
379         data[3] = 255;
380         r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
381         data[0] = 128;
382         data[1] = 128;
383         data[2] = 128;
384         data[3] = 255;
385         r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
386         data[0] = 0;
387         data[1] = 0;
388         data[2] = 0;
389         data[3] = 255;
390         r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
391 }
392
393 static void R_BuildNoTexture(void)
394 {
395         int x, y;
396         unsigned char pix[16][16][4];
397         // this makes a light grey/dark grey checkerboard texture
398         for (y = 0;y < 16;y++)
399         {
400                 for (x = 0;x < 16;x++)
401                 {
402                         if ((y < 8) ^ (x < 8))
403                         {
404                                 pix[y][x][0] = 128;
405                                 pix[y][x][1] = 128;
406                                 pix[y][x][2] = 128;
407                                 pix[y][x][3] = 255;
408                         }
409                         else
410                         {
411                                 pix[y][x][0] = 64;
412                                 pix[y][x][1] = 64;
413                                 pix[y][x][2] = 64;
414                                 pix[y][x][3] = 255;
415                         }
416                 }
417         }
418         r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, -1, NULL);
419 }
420
421 static void R_BuildWhiteCube(void)
422 {
423         unsigned char data[6*1*1*4];
424         memset(data, 255, sizeof(data));
425         r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
426 }
427
428 static void R_BuildNormalizationCube(void)
429 {
430         int x, y, side;
431         vec3_t v;
432         vec_t s, t, intensity;
433 #define NORMSIZE 64
434         unsigned char *data;
435         data = (unsigned char *)Mem_Alloc(tempmempool, 6*NORMSIZE*NORMSIZE*4);
436         for (side = 0;side < 6;side++)
437         {
438                 for (y = 0;y < NORMSIZE;y++)
439                 {
440                         for (x = 0;x < NORMSIZE;x++)
441                         {
442                                 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
443                                 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
444                                 switch(side)
445                                 {
446                                 default:
447                                 case 0:
448                                         v[0] = 1;
449                                         v[1] = -t;
450                                         v[2] = -s;
451                                         break;
452                                 case 1:
453                                         v[0] = -1;
454                                         v[1] = -t;
455                                         v[2] = s;
456                                         break;
457                                 case 2:
458                                         v[0] = s;
459                                         v[1] = 1;
460                                         v[2] = t;
461                                         break;
462                                 case 3:
463                                         v[0] = s;
464                                         v[1] = -1;
465                                         v[2] = -t;
466                                         break;
467                                 case 4:
468                                         v[0] = s;
469                                         v[1] = -t;
470                                         v[2] = 1;
471                                         break;
472                                 case 5:
473                                         v[0] = -s;
474                                         v[1] = -t;
475                                         v[2] = -1;
476                                         break;
477                                 }
478                                 intensity = 127.0f / sqrt(DotProduct(v, v));
479                                 data[((side*64+y)*64+x)*4+2] = (unsigned char)(128.0f + intensity * v[0]);
480                                 data[((side*64+y)*64+x)*4+1] = (unsigned char)(128.0f + intensity * v[1]);
481                                 data[((side*64+y)*64+x)*4+0] = (unsigned char)(128.0f + intensity * v[2]);
482                                 data[((side*64+y)*64+x)*4+3] = 255;
483                         }
484                 }
485         }
486         r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
487         Mem_Free(data);
488 }
489
490 static void R_BuildFogTexture(void)
491 {
492         int x, b;
493 #define FOGWIDTH 256
494         unsigned char data1[FOGWIDTH][4];
495         //unsigned char data2[FOGWIDTH][4];
496         double d, r, alpha;
497
498         r_refdef.fogmasktable_start = r_refdef.fog_start;
499         r_refdef.fogmasktable_alpha = r_refdef.fog_alpha;
500         r_refdef.fogmasktable_range = r_refdef.fogrange;
501         r_refdef.fogmasktable_density = r_refdef.fog_density;
502
503         r = r_refdef.fogmasktable_range / FOGMASKTABLEWIDTH;
504         for (x = 0;x < FOGMASKTABLEWIDTH;x++)
505         {
506                 d = (x * r - r_refdef.fogmasktable_start);
507                 if(developer_extra.integer)
508                         Con_DPrintf("%f ", d);
509                 d = max(0, d);
510                 if (r_fog_exp2.integer)
511                         alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d);
512                 else
513                         alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d);
514                 if(developer_extra.integer)
515                         Con_DPrintf(" : %f ", alpha);
516                 alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha;
517                 if(developer_extra.integer)
518                         Con_DPrintf(" = %f\n", alpha);
519                 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
520         }
521
522         for (x = 0;x < FOGWIDTH;x++)
523         {
524                 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
525                 data1[x][0] = b;
526                 data1[x][1] = b;
527                 data1[x][2] = b;
528                 data1[x][3] = 255;
529                 //data2[x][0] = 255 - b;
530                 //data2[x][1] = 255 - b;
531                 //data2[x][2] = 255 - b;
532                 //data2[x][3] = 255;
533         }
534         if (r_texture_fogattenuation)
535         {
536                 R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
537                 //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
538         }
539         else
540         {
541                 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
542                 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
543         }
544 }
545
546 static void R_BuildFogHeightTexture(void)
547 {
548         unsigned char *inpixels;
549         int size;
550         int x;
551         int y;
552         int j;
553         float c[4];
554         float f;
555         inpixels = NULL;
556         strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename));
557         if (r_refdef.fogheighttexturename[0])
558                 inpixels = loadimagepixelsbgra(r_refdef.fogheighttexturename, true, false, false, NULL);
559         if (!inpixels)
560         {
561                 r_refdef.fog_height_tablesize = 0;
562                 if (r_texture_fogheighttexture)
563                         R_FreeTexture(r_texture_fogheighttexture);
564                 r_texture_fogheighttexture = NULL;
565                 if (r_refdef.fog_height_table2d)
566                         Mem_Free(r_refdef.fog_height_table2d);
567                 r_refdef.fog_height_table2d = NULL;
568                 if (r_refdef.fog_height_table1d)
569                         Mem_Free(r_refdef.fog_height_table1d);
570                 r_refdef.fog_height_table1d = NULL;
571                 return;
572         }
573         size = image_width;
574         r_refdef.fog_height_tablesize = size;
575         r_refdef.fog_height_table1d = (unsigned char *)Mem_Alloc(r_main_mempool, size * 4);
576         r_refdef.fog_height_table2d = (unsigned char *)Mem_Alloc(r_main_mempool, size * size * 4);
577         memcpy(r_refdef.fog_height_table1d, inpixels, size * 4);
578         Mem_Free(inpixels);
579         // LadyHavoc: now the magic - what is that table2d for?  it is a cooked
580         // average fog color table accounting for every fog layer between a point
581         // and the camera.  (Note: attenuation is handled separately!)
582         for (y = 0;y < size;y++)
583         {
584                 for (x = 0;x < size;x++)
585                 {
586                         Vector4Clear(c);
587                         f = 0;
588                         if (x < y)
589                         {
590                                 for (j = x;j <= y;j++)
591                                 {
592                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
593                                         f++;
594                                 }
595                         }
596                         else
597                         {
598                                 for (j = x;j >= y;j--)
599                                 {
600                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
601                                         f++;
602                                 }
603                         }
604                         f = 1.0f / f;
605                         r_refdef.fog_height_table2d[(y*size+x)*4+0] = (unsigned char)(c[0] * f);
606                         r_refdef.fog_height_table2d[(y*size+x)*4+1] = (unsigned char)(c[1] * f);
607                         r_refdef.fog_height_table2d[(y*size+x)*4+2] = (unsigned char)(c[2] * f);
608                         r_refdef.fog_height_table2d[(y*size+x)*4+3] = (unsigned char)(c[3] * f);
609                 }
610         }
611         r_texture_fogheighttexture = R_LoadTexture2D(r_main_texturepool, "fogheighttable", size, size, r_refdef.fog_height_table2d, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_CLAMP, -1, NULL);
612 }
613
614 //=======================================================================================================================================================
615
616 static const char *builtinshaderstrings[] =
617 {
618 #include "shader_glsl.h"
619 0
620 };
621
622 //=======================================================================================================================================================
623
624 typedef struct shaderpermutationinfo_s
625 {
626         const char *pretext;
627         const char *name;
628 }
629 shaderpermutationinfo_t;
630
631 typedef struct shadermodeinfo_s
632 {
633         const char *sourcebasename;
634         const char *extension;
635         const char **builtinshaderstrings;
636         const char *pretext;
637         const char *name;
638         char *filename;
639         char *builtinstring;
640         int builtincrc;
641 }
642 shadermodeinfo_t;
643
644 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
645 shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
646 {
647         {"#define USEDIFFUSE\n", " diffuse"},
648         {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
649         {"#define USEVIEWTINT\n", " viewtint"},
650         {"#define USECOLORMAPPING\n", " colormapping"},
651         {"#define USESATURATION\n", " saturation"},
652         {"#define USEFOGINSIDE\n", " foginside"},
653         {"#define USEFOGOUTSIDE\n", " fogoutside"},
654         {"#define USEFOGHEIGHTTEXTURE\n", " fogheighttexture"},
655         {"#define USEFOGALPHAHACK\n", " fogalphahack"},
656         {"#define USEGAMMARAMPS\n", " gammaramps"},
657         {"#define USECUBEFILTER\n", " cubefilter"},
658         {"#define USEGLOW\n", " glow"},
659         {"#define USEBLOOM\n", " bloom"},
660         {"#define USESPECULAR\n", " specular"},
661         {"#define USEPOSTPROCESSING\n", " postprocessing"},
662         {"#define USEREFLECTION\n", " reflection"},
663         {"#define USEOFFSETMAPPING\n", " offsetmapping"},
664         {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
665         {"#define USESHADOWMAP2D\n", " shadowmap2d"},
666         {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm
667         {"#define USESHADOWMAPORTHO\n", " shadowmaportho"},
668         {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
669         {"#define USEALPHAKILL\n", " alphakill"},
670         {"#define USEREFLECTCUBE\n", " reflectcube"},
671         {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"},
672         {"#define USEBOUNCEGRID\n", " bouncegrid"},
673         {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm
674         {"#define USETRIPPY\n", " trippy"},
675         {"#define USEDEPTHRGB\n", " depthrgb"},
676         {"#define USEALPHAGENVERTEX\n", " alphagenvertex"},
677         {"#define USESKELETAL\n", " skeletal"},
678         {"#define USEOCCLUDE\n", " occlude"}
679 };
680
681 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
682 shadermodeinfo_t shadermodeinfo[SHADERLANGUAGE_COUNT][SHADERMODE_COUNT] =
683 {
684         // SHADERLANGUAGE_GLSL
685         {
686                 {"combined", "glsl", builtinshaderstrings, "#define MODE_GENERIC\n", " generic"},
687                 {"combined", "glsl", builtinshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
688                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
689                 {"combined", "glsl", builtinshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
690                 {"combined", "glsl", builtinshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
691                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
692                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
693                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
694                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
695                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
696                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTGRID\n", " lightgrid"},
697                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
698                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
699                 {"combined", "glsl", builtinshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
700                 {"combined", "glsl", builtinshaderstrings, "#define MODE_WATER\n", " water"},
701                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
702                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
703         },
704 };
705
706 struct r_glsl_permutation_s;
707 typedef struct r_glsl_permutation_s
708 {
709         /// hash lookup data
710         struct r_glsl_permutation_s *hashnext;
711         unsigned int mode;
712         dpuint64 permutation;
713
714         /// indicates if we have tried compiling this permutation already
715         qboolean compiled;
716         /// 0 if compilation failed
717         int program;
718         // texture units assigned to each detected uniform
719         int tex_Texture_First;
720         int tex_Texture_Second;
721         int tex_Texture_GammaRamps;
722         int tex_Texture_Normal;
723         int tex_Texture_Color;
724         int tex_Texture_Gloss;
725         int tex_Texture_Glow;
726         int tex_Texture_SecondaryNormal;
727         int tex_Texture_SecondaryColor;
728         int tex_Texture_SecondaryGloss;
729         int tex_Texture_SecondaryGlow;
730         int tex_Texture_Pants;
731         int tex_Texture_Shirt;
732         int tex_Texture_FogHeightTexture;
733         int tex_Texture_FogMask;
734         int tex_Texture_LightGrid;
735         int tex_Texture_Lightmap;
736         int tex_Texture_Deluxemap;
737         int tex_Texture_Attenuation;
738         int tex_Texture_Cube;
739         int tex_Texture_Refraction;
740         int tex_Texture_Reflection;
741         int tex_Texture_ShadowMap2D;
742         int tex_Texture_CubeProjection;
743         int tex_Texture_ScreenNormalMap;
744         int tex_Texture_ScreenDiffuse;
745         int tex_Texture_ScreenSpecular;
746         int tex_Texture_ReflectMask;
747         int tex_Texture_ReflectCube;
748         int tex_Texture_BounceGrid;
749         /// locations of detected uniforms in program object, or -1 if not found
750         int loc_Texture_First;
751         int loc_Texture_Second;
752         int loc_Texture_GammaRamps;
753         int loc_Texture_Normal;
754         int loc_Texture_Color;
755         int loc_Texture_Gloss;
756         int loc_Texture_Glow;
757         int loc_Texture_SecondaryNormal;
758         int loc_Texture_SecondaryColor;
759         int loc_Texture_SecondaryGloss;
760         int loc_Texture_SecondaryGlow;
761         int loc_Texture_Pants;
762         int loc_Texture_Shirt;
763         int loc_Texture_FogHeightTexture;
764         int loc_Texture_FogMask;
765         int loc_Texture_LightGrid;
766         int loc_Texture_Lightmap;
767         int loc_Texture_Deluxemap;
768         int loc_Texture_Attenuation;
769         int loc_Texture_Cube;
770         int loc_Texture_Refraction;
771         int loc_Texture_Reflection;
772         int loc_Texture_ShadowMap2D;
773         int loc_Texture_CubeProjection;
774         int loc_Texture_ScreenNormalMap;
775         int loc_Texture_ScreenDiffuse;
776         int loc_Texture_ScreenSpecular;
777         int loc_Texture_ReflectMask;
778         int loc_Texture_ReflectCube;
779         int loc_Texture_BounceGrid;
780         int loc_Alpha;
781         int loc_BloomBlur_Parameters;
782         int loc_ClientTime;
783         int loc_Color_Ambient;
784         int loc_Color_Diffuse;
785         int loc_Color_Specular;
786         int loc_Color_Glow;
787         int loc_Color_Pants;
788         int loc_Color_Shirt;
789         int loc_DeferredColor_Ambient;
790         int loc_DeferredColor_Diffuse;
791         int loc_DeferredColor_Specular;
792         int loc_DeferredMod_Diffuse;
793         int loc_DeferredMod_Specular;
794         int loc_DistortScaleRefractReflect;
795         int loc_EyePosition;
796         int loc_FogColor;
797         int loc_FogHeightFade;
798         int loc_FogPlane;
799         int loc_FogPlaneViewDist;
800         int loc_FogRangeRecip;
801         int loc_LightColor;
802         int loc_LightDir;
803         int loc_LightGridMatrix;
804         int loc_LightGridNormalMatrix;
805         int loc_LightPosition;
806         int loc_OffsetMapping_ScaleSteps;
807         int loc_OffsetMapping_LodDistance;
808         int loc_OffsetMapping_Bias;
809         int loc_PixelSize;
810         int loc_ReflectColor;
811         int loc_ReflectFactor;
812         int loc_ReflectOffset;
813         int loc_RefractColor;
814         int loc_Saturation;
815         int loc_ScreenCenterRefractReflect;
816         int loc_ScreenScaleRefractReflect;
817         int loc_ScreenToDepth;
818         int loc_ShadowMap_Parameters;
819         int loc_ShadowMap_TextureScale;
820         int loc_SpecularPower;
821         int loc_Skeletal_Transform12;
822         int loc_UserVec1;
823         int loc_UserVec2;
824         int loc_UserVec3;
825         int loc_UserVec4;
826         int loc_ColorFringe;
827         int loc_ViewTintColor;
828         int loc_ViewToLight;
829         int loc_ModelToLight;
830         int loc_TexMatrix;
831         int loc_BackgroundTexMatrix;
832         int loc_ModelViewProjectionMatrix;
833         int loc_ModelViewMatrix;
834         int loc_PixelToScreenTexCoord;
835         int loc_ModelToReflectCube;
836         int loc_ShadowMapMatrix;
837         int loc_BloomColorSubtract;
838         int loc_NormalmapScrollBlend;
839         int loc_BounceGridMatrix;
840         int loc_BounceGridIntensity;
841         /// uniform block bindings
842         int ubibind_Skeletal_Transform12_UniformBlock;
843         /// uniform block indices
844         int ubiloc_Skeletal_Transform12_UniformBlock;
845 }
846 r_glsl_permutation_t;
847
848 #define SHADERPERMUTATION_HASHSIZE 256
849
850
851 // non-degradable "lightweight" shader parameters to keep the permutations simpler
852 // these can NOT degrade! only use for simple stuff
853 enum
854 {
855         SHADERSTATICPARM_SATURATION_REDCOMPENSATE = 0, ///< red compensation filter for saturation
856         SHADERSTATICPARM_EXACTSPECULARMATH = 1, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
857         SHADERSTATICPARM_POSTPROCESS_USERVEC1 = 2, ///< postprocess uservec1 is enabled
858         SHADERSTATICPARM_POSTPROCESS_USERVEC2 = 3, ///< postprocess uservec2 is enabled
859         SHADERSTATICPARM_POSTPROCESS_USERVEC3 = 4, ///< postprocess uservec3 is enabled
860         SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5,  ///< postprocess uservec4 is enabled
861         SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending
862         SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7,  ///< LOD for offsetmapping
863         SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1
864         SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2
865         SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
866         SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
867         SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
868         SHADERSTATICPARM_FXAA = 13 ///< fast approximate anti aliasing
869 };
870 #define SHADERSTATICPARMS_COUNT 14
871
872 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
873 static int shaderstaticparms_count = 0;
874
875 static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0};
876 #define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F))
877
878 extern qboolean r_shadow_shadowmapsampler;
879 extern int r_shadow_shadowmappcf;
880 qboolean R_CompileShader_CheckStaticParms(void)
881 {
882         static int r_compileshader_staticparms_save[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5];
883         memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
884         memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
885
886         // detect all
887         if (r_glsl_saturation_redcompensate.integer)
888                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SATURATION_REDCOMPENSATE);
889         if (r_glsl_vertextextureblend_usebothalphas.integer)
890                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS);
891         if (r_shadow_glossexact.integer)
892                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_EXACTSPECULARMATH);
893         if (r_glsl_postprocess.integer)
894         {
895                 if (r_glsl_postprocess_uservec1_enable.integer)
896                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC1);
897                 if (r_glsl_postprocess_uservec2_enable.integer)
898                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC2);
899                 if (r_glsl_postprocess_uservec3_enable.integer)
900                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC3);
901                 if (r_glsl_postprocess_uservec4_enable.integer)
902                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
903         }
904         if (r_fxaa.integer)
905                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_FXAA);
906         if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
907                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
908
909         if (r_shadow_shadowmapsampler)
910                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER);
911         if (r_shadow_shadowmappcf > 1)
912                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2);
913         else if (r_shadow_shadowmappcf)
914                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1);
915         if (r_celshading.integer)
916                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING);
917         if (r_celoutlines.integer)
918                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES);
919
920         return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
921 }
922
923 #define R_COMPILESHADER_STATICPARM_EMIT(p, n) \
924         if(r_compileshader_staticparms[(p) >> 5] & (1 << ((p) & 0x1F))) \
925                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \
926         else \
927                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n"
928 static void R_CompileShader_AddStaticParms(unsigned int mode, dpuint64 permutation)
929 {
930         shaderstaticparms_count = 0;
931
932         // emit all
933         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SATURATION_REDCOMPENSATE, "SATURATION_REDCOMPENSATE");
934         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_EXACTSPECULARMATH, "USEEXACTSPECULARMATH");
935         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC1, "USERVEC1");
936         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC2, "USERVEC2");
937         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC3, "USERVEC3");
938         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4");
939         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS");
940         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD");
941         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1");
942         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2");
943         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
944         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
945         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
946         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
947 }
948
949 /// information about each possible shader permutation
950 r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
951 /// currently selected permutation
952 r_glsl_permutation_t *r_glsl_permutation;
953 /// storage for permutations linked in the hash table
954 memexpandablearray_t r_glsl_permutationarray;
955
956 static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, dpuint64 permutation)
957 {
958         //unsigned int hashdepth = 0;
959         unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
960         r_glsl_permutation_t *p;
961         for (p = r_glsl_permutationhash[mode][hashindex];p;p = p->hashnext)
962         {
963                 if (p->mode == mode && p->permutation == permutation)
964                 {
965                         //if (hashdepth > 10)
966                         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
967                         return p;
968                 }
969                 //hashdepth++;
970         }
971         p = (r_glsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_glsl_permutationarray);
972         p->mode = mode;
973         p->permutation = permutation;
974         p->hashnext = r_glsl_permutationhash[mode][hashindex];
975         r_glsl_permutationhash[mode][hashindex] = p;
976         //if (hashdepth > 10)
977         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
978         return p;
979 }
980
981 static char *R_ShaderStrCat(const char **strings)
982 {
983         char *string, *s;
984         const char **p = strings;
985         const char *t;
986         size_t len = 0;
987         for (p = strings;(t = *p);p++)
988                 len += strlen(t);
989         len++;
990         s = string = (char *)Mem_Alloc(r_main_mempool, len);
991         len = 0;
992         for (p = strings;(t = *p);p++)
993         {
994                 len = strlen(t);
995                 memcpy(s, t, len);
996                 s += len;
997         }
998         *s = 0;
999         return string;
1000 }
1001
1002 static char *R_ShaderStrCat(const char **strings);
1003 static void R_InitShaderModeInfo(void)
1004 {
1005         int i, language;
1006         shadermodeinfo_t *modeinfo;
1007         // we have a bunch of things to compute that weren't calculated at engine compile time - all filenames should have a crc of the builtin strings to prevent accidental overrides (any customization must be updated to match engine)
1008         for (language = 0; language < SHADERLANGUAGE_COUNT; language++)
1009         {
1010                 for (i = 0; i < SHADERMODE_COUNT; i++)
1011                 {
1012                         char filename[MAX_QPATH];
1013                         modeinfo = &shadermodeinfo[language][i];
1014                         modeinfo->builtinstring = R_ShaderStrCat(modeinfo->builtinshaderstrings);
1015                         modeinfo->builtincrc = CRC_Block((const unsigned char *)modeinfo->builtinstring, strlen(modeinfo->builtinstring));
1016                         dpsnprintf(filename, sizeof(filename), "%s/%s_crc%i.%s", modeinfo->extension, modeinfo->sourcebasename, modeinfo->builtincrc, modeinfo->extension);
1017                         modeinfo->filename = Mem_strdup(r_main_mempool, filename);
1018                 }
1019         }
1020 }
1021
1022 static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qboolean printfromdisknotice, qboolean builtinonly)
1023 {
1024         char *shaderstring;
1025         // if the mode has no filename we have to return the builtin string
1026         if (builtinonly || !modeinfo->filename)
1027                 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1028         // note that FS_LoadFile appends a 0 byte to make it a valid string
1029         shaderstring = (char *)FS_LoadFile(modeinfo->filename, r_main_mempool, false, NULL);
1030         if (shaderstring)
1031         {
1032                 if (printfromdisknotice)
1033                         Con_DPrintf("Loading shaders from file %s...\n", modeinfo->filename);
1034                 return shaderstring;
1035         }
1036         // fall back to builtinstring
1037         return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1038 }
1039
1040 static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, dpuint64 permutation)
1041 {
1042         int i;
1043         int ubibind;
1044         int sampler;
1045         shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode];
1046         char *sourcestring;
1047         char permutationname[256];
1048         int vertstrings_count = 0;
1049         int geomstrings_count = 0;
1050         int fragstrings_count = 0;
1051         const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1052         const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1053         const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1054
1055         if (p->compiled)
1056                 return;
1057         p->compiled = true;
1058         p->program = 0;
1059
1060         permutationname[0] = 0;
1061         sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false);
1062
1063         strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
1064
1065         // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object)
1066         if(vid.support.glshaderversion >= 140)
1067         {
1068                 vertstrings_list[vertstrings_count++] = "#version 140\n";
1069                 geomstrings_list[geomstrings_count++] = "#version 140\n";
1070                 fragstrings_list[fragstrings_count++] = "#version 140\n";
1071                 vertstrings_list[vertstrings_count++] = "#define GLSL140\n";
1072                 geomstrings_list[geomstrings_count++] = "#define GLSL140\n";
1073                 fragstrings_list[fragstrings_count++] = "#define GLSL140\n";
1074         }
1075         // if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad)
1076         else if(vid.support.glshaderversion >= 130)
1077         {
1078                 vertstrings_list[vertstrings_count++] = "#version 130\n";
1079                 geomstrings_list[geomstrings_count++] = "#version 130\n";
1080                 fragstrings_list[fragstrings_count++] = "#version 130\n";
1081                 vertstrings_list[vertstrings_count++] = "#define GLSL130\n";
1082                 geomstrings_list[geomstrings_count++] = "#define GLSL130\n";
1083                 fragstrings_list[fragstrings_count++] = "#define GLSL130\n";
1084         }
1085         // if we can do #version 120, we should (this adds the invariant keyword)
1086         else if(vid.support.glshaderversion >= 120)
1087         {
1088                 vertstrings_list[vertstrings_count++] = "#version 120\n";
1089                 geomstrings_list[geomstrings_count++] = "#version 120\n";
1090                 fragstrings_list[fragstrings_count++] = "#version 120\n";
1091                 vertstrings_list[vertstrings_count++] = "#define GLSL120\n";
1092                 geomstrings_list[geomstrings_count++] = "#define GLSL120\n";
1093                 fragstrings_list[fragstrings_count++] = "#define GLSL120\n";
1094         }
1095         // GLES also adds several things from GLSL120
1096         switch(vid.renderpath)
1097         {
1098         case RENDERPATH_GLES2:
1099                 vertstrings_list[vertstrings_count++] = "#define GLES\n";
1100                 geomstrings_list[geomstrings_count++] = "#define GLES\n";
1101                 fragstrings_list[fragstrings_count++] = "#define GLES\n";
1102                 break;
1103         default:
1104                 break;
1105         }
1106
1107         // the first pretext is which type of shader to compile as
1108         // (later these will all be bound together as a program object)
1109         vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
1110         geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
1111         fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
1112
1113         // the second pretext is the mode (for example a light source)
1114         vertstrings_list[vertstrings_count++] = modeinfo->pretext;
1115         geomstrings_list[geomstrings_count++] = modeinfo->pretext;
1116         fragstrings_list[fragstrings_count++] = modeinfo->pretext;
1117         strlcat(permutationname, modeinfo->name, sizeof(permutationname));
1118
1119         // now add all the permutation pretexts
1120         for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1121         {
1122                 if (permutation & (1ll<<i))
1123                 {
1124                         vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
1125                         geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
1126                         fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
1127                         strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
1128                 }
1129                 else
1130                 {
1131                         // keep line numbers correct
1132                         vertstrings_list[vertstrings_count++] = "\n";
1133                         geomstrings_list[geomstrings_count++] = "\n";
1134                         fragstrings_list[fragstrings_count++] = "\n";
1135                 }
1136         }
1137
1138         // add static parms
1139         R_CompileShader_AddStaticParms(mode, permutation);
1140         memcpy((char *)(vertstrings_list + vertstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1141         vertstrings_count += shaderstaticparms_count;
1142         memcpy((char *)(geomstrings_list + geomstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1143         geomstrings_count += shaderstaticparms_count;
1144         memcpy((char *)(fragstrings_list + fragstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1145         fragstrings_count += shaderstaticparms_count;
1146
1147         // now append the shader text itself
1148         vertstrings_list[vertstrings_count++] = sourcestring;
1149         geomstrings_list[geomstrings_count++] = sourcestring;
1150         fragstrings_list[fragstrings_count++] = sourcestring;
1151
1152         // we don't currently use geometry shaders for anything, so just empty the list
1153         geomstrings_count = 0;
1154
1155         // compile the shader program
1156         if (vertstrings_count + geomstrings_count + fragstrings_count)
1157                 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1158         if (p->program)
1159         {
1160                 CHECKGLERROR
1161                 qglUseProgram(p->program);CHECKGLERROR
1162                 // look up all the uniform variable names we care about, so we don't
1163                 // have to look them up every time we set them
1164
1165 #if 0
1166                 // debugging aid
1167                 {
1168                         GLint activeuniformindex = 0;
1169                         GLint numactiveuniforms = 0;
1170                         char uniformname[128];
1171                         GLsizei uniformnamelength = 0;
1172                         GLint uniformsize = 0;
1173                         GLenum uniformtype = 0;
1174                         memset(uniformname, 0, sizeof(uniformname));
1175                         qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms);
1176                         Con_Printf("Shader has %i uniforms\n", numactiveuniforms);
1177                         for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++)
1178                         {
1179                                 qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname);
1180                                 Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype);
1181                         }
1182                 }
1183 #endif
1184
1185                 p->loc_Texture_First              = qglGetUniformLocation(p->program, "Texture_First");
1186                 p->loc_Texture_Second             = qglGetUniformLocation(p->program, "Texture_Second");
1187                 p->loc_Texture_GammaRamps         = qglGetUniformLocation(p->program, "Texture_GammaRamps");
1188                 p->loc_Texture_Normal             = qglGetUniformLocation(p->program, "Texture_Normal");
1189                 p->loc_Texture_Color              = qglGetUniformLocation(p->program, "Texture_Color");
1190                 p->loc_Texture_Gloss              = qglGetUniformLocation(p->program, "Texture_Gloss");
1191                 p->loc_Texture_Glow               = qglGetUniformLocation(p->program, "Texture_Glow");
1192                 p->loc_Texture_SecondaryNormal    = qglGetUniformLocation(p->program, "Texture_SecondaryNormal");
1193                 p->loc_Texture_SecondaryColor     = qglGetUniformLocation(p->program, "Texture_SecondaryColor");
1194                 p->loc_Texture_SecondaryGloss     = qglGetUniformLocation(p->program, "Texture_SecondaryGloss");
1195                 p->loc_Texture_SecondaryGlow      = qglGetUniformLocation(p->program, "Texture_SecondaryGlow");
1196                 p->loc_Texture_Pants              = qglGetUniformLocation(p->program, "Texture_Pants");
1197                 p->loc_Texture_Shirt              = qglGetUniformLocation(p->program, "Texture_Shirt");
1198                 p->loc_Texture_FogHeightTexture   = qglGetUniformLocation(p->program, "Texture_FogHeightTexture");
1199                 p->loc_Texture_FogMask            = qglGetUniformLocation(p->program, "Texture_FogMask");
1200                 p->loc_Texture_LightGrid          = qglGetUniformLocation(p->program, "Texture_LightGrid");
1201                 p->loc_Texture_Lightmap           = qglGetUniformLocation(p->program, "Texture_Lightmap");
1202                 p->loc_Texture_Deluxemap          = qglGetUniformLocation(p->program, "Texture_Deluxemap");
1203                 p->loc_Texture_Attenuation        = qglGetUniformLocation(p->program, "Texture_Attenuation");
1204                 p->loc_Texture_Cube               = qglGetUniformLocation(p->program, "Texture_Cube");
1205                 p->loc_Texture_Refraction         = qglGetUniformLocation(p->program, "Texture_Refraction");
1206                 p->loc_Texture_Reflection         = qglGetUniformLocation(p->program, "Texture_Reflection");
1207                 p->loc_Texture_ShadowMap2D        = qglGetUniformLocation(p->program, "Texture_ShadowMap2D");
1208                 p->loc_Texture_CubeProjection     = qglGetUniformLocation(p->program, "Texture_CubeProjection");
1209                 p->loc_Texture_ScreenNormalMap    = qglGetUniformLocation(p->program, "Texture_ScreenNormalMap");
1210                 p->loc_Texture_ScreenDiffuse      = qglGetUniformLocation(p->program, "Texture_ScreenDiffuse");
1211                 p->loc_Texture_ScreenSpecular     = qglGetUniformLocation(p->program, "Texture_ScreenSpecular");
1212                 p->loc_Texture_ReflectMask        = qglGetUniformLocation(p->program, "Texture_ReflectMask");
1213                 p->loc_Texture_ReflectCube        = qglGetUniformLocation(p->program, "Texture_ReflectCube");
1214                 p->loc_Texture_BounceGrid         = qglGetUniformLocation(p->program, "Texture_BounceGrid");
1215                 p->loc_Alpha                      = qglGetUniformLocation(p->program, "Alpha");
1216                 p->loc_BloomBlur_Parameters       = qglGetUniformLocation(p->program, "BloomBlur_Parameters");
1217                 p->loc_ClientTime                 = qglGetUniformLocation(p->program, "ClientTime");
1218                 p->loc_Color_Ambient              = qglGetUniformLocation(p->program, "Color_Ambient");
1219                 p->loc_Color_Diffuse              = qglGetUniformLocation(p->program, "Color_Diffuse");
1220                 p->loc_Color_Specular             = qglGetUniformLocation(p->program, "Color_Specular");
1221                 p->loc_Color_Glow                 = qglGetUniformLocation(p->program, "Color_Glow");
1222                 p->loc_Color_Pants                = qglGetUniformLocation(p->program, "Color_Pants");
1223                 p->loc_Color_Shirt                = qglGetUniformLocation(p->program, "Color_Shirt");
1224                 p->loc_DeferredColor_Ambient      = qglGetUniformLocation(p->program, "DeferredColor_Ambient");
1225                 p->loc_DeferredColor_Diffuse      = qglGetUniformLocation(p->program, "DeferredColor_Diffuse");
1226                 p->loc_DeferredColor_Specular     = qglGetUniformLocation(p->program, "DeferredColor_Specular");
1227                 p->loc_DeferredMod_Diffuse        = qglGetUniformLocation(p->program, "DeferredMod_Diffuse");
1228                 p->loc_DeferredMod_Specular       = qglGetUniformLocation(p->program, "DeferredMod_Specular");
1229                 p->loc_DistortScaleRefractReflect = qglGetUniformLocation(p->program, "DistortScaleRefractReflect");
1230                 p->loc_EyePosition                = qglGetUniformLocation(p->program, "EyePosition");
1231                 p->loc_FogColor                   = qglGetUniformLocation(p->program, "FogColor");
1232                 p->loc_FogHeightFade              = qglGetUniformLocation(p->program, "FogHeightFade");
1233                 p->loc_FogPlane                   = qglGetUniformLocation(p->program, "FogPlane");
1234                 p->loc_FogPlaneViewDist           = qglGetUniformLocation(p->program, "FogPlaneViewDist");
1235                 p->loc_FogRangeRecip              = qglGetUniformLocation(p->program, "FogRangeRecip");
1236                 p->loc_LightColor                 = qglGetUniformLocation(p->program, "LightColor");
1237                 p->loc_LightGridMatrix            = qglGetUniformLocation(p->program, "LightGridMatrix");
1238                 p->loc_LightGridNormalMatrix      = qglGetUniformLocation(p->program, "LightGridNormalMatrix");
1239                 p->loc_LightDir                   = qglGetUniformLocation(p->program, "LightDir");
1240                 p->loc_LightPosition              = qglGetUniformLocation(p->program, "LightPosition");
1241                 p->loc_OffsetMapping_ScaleSteps   = qglGetUniformLocation(p->program, "OffsetMapping_ScaleSteps");
1242                 p->loc_OffsetMapping_LodDistance  = qglGetUniformLocation(p->program, "OffsetMapping_LodDistance");
1243                 p->loc_OffsetMapping_Bias         = qglGetUniformLocation(p->program, "OffsetMapping_Bias");
1244                 p->loc_PixelSize                  = qglGetUniformLocation(p->program, "PixelSize");
1245                 p->loc_ReflectColor               = qglGetUniformLocation(p->program, "ReflectColor");
1246                 p->loc_ReflectFactor              = qglGetUniformLocation(p->program, "ReflectFactor");
1247                 p->loc_ReflectOffset              = qglGetUniformLocation(p->program, "ReflectOffset");
1248                 p->loc_RefractColor               = qglGetUniformLocation(p->program, "RefractColor");
1249                 p->loc_Saturation                 = qglGetUniformLocation(p->program, "Saturation");
1250                 p->loc_ScreenCenterRefractReflect = qglGetUniformLocation(p->program, "ScreenCenterRefractReflect");
1251                 p->loc_ScreenScaleRefractReflect  = qglGetUniformLocation(p->program, "ScreenScaleRefractReflect");
1252                 p->loc_ScreenToDepth              = qglGetUniformLocation(p->program, "ScreenToDepth");
1253                 p->loc_ShadowMap_Parameters       = qglGetUniformLocation(p->program, "ShadowMap_Parameters");
1254                 p->loc_ShadowMap_TextureScale     = qglGetUniformLocation(p->program, "ShadowMap_TextureScale");
1255                 p->loc_SpecularPower              = qglGetUniformLocation(p->program, "SpecularPower");
1256                 p->loc_UserVec1                   = qglGetUniformLocation(p->program, "UserVec1");
1257                 p->loc_UserVec2                   = qglGetUniformLocation(p->program, "UserVec2");
1258                 p->loc_UserVec3                   = qglGetUniformLocation(p->program, "UserVec3");
1259                 p->loc_UserVec4                   = qglGetUniformLocation(p->program, "UserVec4");
1260                 p->loc_ColorFringe                = qglGetUniformLocation(p->program, "ColorFringe");
1261                 p->loc_ViewTintColor              = qglGetUniformLocation(p->program, "ViewTintColor");
1262                 p->loc_ViewToLight                = qglGetUniformLocation(p->program, "ViewToLight");
1263                 p->loc_ModelToLight               = qglGetUniformLocation(p->program, "ModelToLight");
1264                 p->loc_TexMatrix                  = qglGetUniformLocation(p->program, "TexMatrix");
1265                 p->loc_BackgroundTexMatrix        = qglGetUniformLocation(p->program, "BackgroundTexMatrix");
1266                 p->loc_ModelViewMatrix            = qglGetUniformLocation(p->program, "ModelViewMatrix");
1267                 p->loc_ModelViewProjectionMatrix  = qglGetUniformLocation(p->program, "ModelViewProjectionMatrix");
1268                 p->loc_PixelToScreenTexCoord      = qglGetUniformLocation(p->program, "PixelToScreenTexCoord");
1269                 p->loc_ModelToReflectCube         = qglGetUniformLocation(p->program, "ModelToReflectCube");
1270                 p->loc_ShadowMapMatrix            = qglGetUniformLocation(p->program, "ShadowMapMatrix");
1271                 p->loc_BloomColorSubtract         = qglGetUniformLocation(p->program, "BloomColorSubtract");
1272                 p->loc_NormalmapScrollBlend       = qglGetUniformLocation(p->program, "NormalmapScrollBlend");
1273                 p->loc_BounceGridMatrix           = qglGetUniformLocation(p->program, "BounceGridMatrix");
1274                 p->loc_BounceGridIntensity        = qglGetUniformLocation(p->program, "BounceGridIntensity");
1275                 // initialize the samplers to refer to the texture units we use
1276                 p->tex_Texture_First = -1;
1277                 p->tex_Texture_Second = -1;
1278                 p->tex_Texture_GammaRamps = -1;
1279                 p->tex_Texture_Normal = -1;
1280                 p->tex_Texture_Color = -1;
1281                 p->tex_Texture_Gloss = -1;
1282                 p->tex_Texture_Glow = -1;
1283                 p->tex_Texture_SecondaryNormal = -1;
1284                 p->tex_Texture_SecondaryColor = -1;
1285                 p->tex_Texture_SecondaryGloss = -1;
1286                 p->tex_Texture_SecondaryGlow = -1;
1287                 p->tex_Texture_Pants = -1;
1288                 p->tex_Texture_Shirt = -1;
1289                 p->tex_Texture_FogHeightTexture = -1;
1290                 p->tex_Texture_FogMask = -1;
1291                 p->tex_Texture_LightGrid = -1;
1292                 p->tex_Texture_Lightmap = -1;
1293                 p->tex_Texture_Deluxemap = -1;
1294                 p->tex_Texture_Attenuation = -1;
1295                 p->tex_Texture_Cube = -1;
1296                 p->tex_Texture_Refraction = -1;
1297                 p->tex_Texture_Reflection = -1;
1298                 p->tex_Texture_ShadowMap2D = -1;
1299                 p->tex_Texture_CubeProjection = -1;
1300                 p->tex_Texture_ScreenNormalMap = -1;
1301                 p->tex_Texture_ScreenDiffuse = -1;
1302                 p->tex_Texture_ScreenSpecular = -1;
1303                 p->tex_Texture_ReflectMask = -1;
1304                 p->tex_Texture_ReflectCube = -1;
1305                 p->tex_Texture_BounceGrid = -1;
1306                 // bind the texture samplers in use
1307                 sampler = 0;
1308                 if (p->loc_Texture_First           >= 0) {p->tex_Texture_First            = sampler;qglUniform1i(p->loc_Texture_First           , sampler);sampler++;}
1309                 if (p->loc_Texture_Second          >= 0) {p->tex_Texture_Second           = sampler;qglUniform1i(p->loc_Texture_Second          , sampler);sampler++;}
1310                 if (p->loc_Texture_GammaRamps      >= 0) {p->tex_Texture_GammaRamps       = sampler;qglUniform1i(p->loc_Texture_GammaRamps      , sampler);sampler++;}
1311                 if (p->loc_Texture_Normal          >= 0) {p->tex_Texture_Normal           = sampler;qglUniform1i(p->loc_Texture_Normal          , sampler);sampler++;}
1312                 if (p->loc_Texture_Color           >= 0) {p->tex_Texture_Color            = sampler;qglUniform1i(p->loc_Texture_Color           , sampler);sampler++;}
1313                 if (p->loc_Texture_Gloss           >= 0) {p->tex_Texture_Gloss            = sampler;qglUniform1i(p->loc_Texture_Gloss           , sampler);sampler++;}
1314                 if (p->loc_Texture_Glow            >= 0) {p->tex_Texture_Glow             = sampler;qglUniform1i(p->loc_Texture_Glow            , sampler);sampler++;}
1315                 if (p->loc_Texture_SecondaryNormal >= 0) {p->tex_Texture_SecondaryNormal  = sampler;qglUniform1i(p->loc_Texture_SecondaryNormal , sampler);sampler++;}
1316                 if (p->loc_Texture_SecondaryColor  >= 0) {p->tex_Texture_SecondaryColor   = sampler;qglUniform1i(p->loc_Texture_SecondaryColor  , sampler);sampler++;}
1317                 if (p->loc_Texture_SecondaryGloss  >= 0) {p->tex_Texture_SecondaryGloss   = sampler;qglUniform1i(p->loc_Texture_SecondaryGloss  , sampler);sampler++;}
1318                 if (p->loc_Texture_SecondaryGlow   >= 0) {p->tex_Texture_SecondaryGlow    = sampler;qglUniform1i(p->loc_Texture_SecondaryGlow   , sampler);sampler++;}
1319                 if (p->loc_Texture_Pants           >= 0) {p->tex_Texture_Pants            = sampler;qglUniform1i(p->loc_Texture_Pants           , sampler);sampler++;}
1320                 if (p->loc_Texture_Shirt           >= 0) {p->tex_Texture_Shirt            = sampler;qglUniform1i(p->loc_Texture_Shirt           , sampler);sampler++;}
1321                 if (p->loc_Texture_FogHeightTexture>= 0) {p->tex_Texture_FogHeightTexture = sampler;qglUniform1i(p->loc_Texture_FogHeightTexture, sampler);sampler++;}
1322                 if (p->loc_Texture_FogMask         >= 0) {p->tex_Texture_FogMask          = sampler;qglUniform1i(p->loc_Texture_FogMask         , sampler);sampler++;}
1323                 if (p->loc_Texture_LightGrid       >= 0) {p->tex_Texture_LightGrid        = sampler;qglUniform1i(p->loc_Texture_LightGrid       , sampler);sampler++;}
1324                 if (p->loc_Texture_Lightmap        >= 0) {p->tex_Texture_Lightmap         = sampler;qglUniform1i(p->loc_Texture_Lightmap        , sampler);sampler++;}
1325                 if (p->loc_Texture_Deluxemap       >= 0) {p->tex_Texture_Deluxemap        = sampler;qglUniform1i(p->loc_Texture_Deluxemap       , sampler);sampler++;}
1326                 if (p->loc_Texture_Attenuation     >= 0) {p->tex_Texture_Attenuation      = sampler;qglUniform1i(p->loc_Texture_Attenuation     , sampler);sampler++;}
1327                 if (p->loc_Texture_Cube            >= 0) {p->tex_Texture_Cube             = sampler;qglUniform1i(p->loc_Texture_Cube            , sampler);sampler++;}
1328                 if (p->loc_Texture_Refraction      >= 0) {p->tex_Texture_Refraction       = sampler;qglUniform1i(p->loc_Texture_Refraction      , sampler);sampler++;}
1329                 if (p->loc_Texture_Reflection      >= 0) {p->tex_Texture_Reflection       = sampler;qglUniform1i(p->loc_Texture_Reflection      , sampler);sampler++;}
1330                 if (p->loc_Texture_ShadowMap2D     >= 0) {p->tex_Texture_ShadowMap2D      = sampler;qglUniform1i(p->loc_Texture_ShadowMap2D     , sampler);sampler++;}
1331                 if (p->loc_Texture_CubeProjection  >= 0) {p->tex_Texture_CubeProjection   = sampler;qglUniform1i(p->loc_Texture_CubeProjection  , sampler);sampler++;}
1332                 if (p->loc_Texture_ScreenNormalMap >= 0) {p->tex_Texture_ScreenNormalMap  = sampler;qglUniform1i(p->loc_Texture_ScreenNormalMap , sampler);sampler++;}
1333                 if (p->loc_Texture_ScreenDiffuse   >= 0) {p->tex_Texture_ScreenDiffuse    = sampler;qglUniform1i(p->loc_Texture_ScreenDiffuse   , sampler);sampler++;}
1334                 if (p->loc_Texture_ScreenSpecular  >= 0) {p->tex_Texture_ScreenSpecular   = sampler;qglUniform1i(p->loc_Texture_ScreenSpecular  , sampler);sampler++;}
1335                 if (p->loc_Texture_ReflectMask     >= 0) {p->tex_Texture_ReflectMask      = sampler;qglUniform1i(p->loc_Texture_ReflectMask     , sampler);sampler++;}
1336                 if (p->loc_Texture_ReflectCube     >= 0) {p->tex_Texture_ReflectCube      = sampler;qglUniform1i(p->loc_Texture_ReflectCube     , sampler);sampler++;}
1337                 if (p->loc_Texture_BounceGrid      >= 0) {p->tex_Texture_BounceGrid       = sampler;qglUniform1i(p->loc_Texture_BounceGrid      , sampler);sampler++;}
1338                 // get the uniform block indices so we can bind them
1339                 p->ubiloc_Skeletal_Transform12_UniformBlock = -1;
1340 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1341                 p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
1342 #endif
1343                 // clear the uniform block bindings
1344                 p->ubibind_Skeletal_Transform12_UniformBlock = -1;
1345                 // bind the uniform blocks in use
1346                 ubibind = 0;
1347 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1348                 if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;}
1349 #endif
1350                 // we're done compiling and setting up the shader, at least until it is used
1351                 CHECKGLERROR
1352                 Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler);
1353         }
1354         else
1355                 Con_Printf("^1GLSL shader %s failed!  some features may not work properly.\n", permutationname);
1356
1357         // free the strings
1358         if (sourcestring)
1359                 Mem_Free(sourcestring);
1360 }
1361
1362 static void R_SetupShader_SetPermutationGLSL(unsigned int mode, dpuint64 permutation)
1363 {
1364         r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation);
1365         if (r_glsl_permutation != perm)
1366         {
1367                 r_glsl_permutation = perm;
1368                 if (!r_glsl_permutation->program)
1369                 {
1370                         if (!r_glsl_permutation->compiled)
1371                         {
1372                                 Con_DPrintf("Compiling shader mode %u permutation %llx\n", mode, permutation);
1373                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1374                         }
1375                         if (!r_glsl_permutation->program)
1376                         {
1377                                 // remove features until we find a valid permutation
1378                                 int i;
1379                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1380                                 {
1381                                         // reduce i more quickly whenever it would not remove any bits
1382                                         dpuint64 j = 1ll<<(SHADERPERMUTATION_COUNT-1-i);
1383                                         if (!(permutation & j))
1384                                                 continue;
1385                                         permutation -= j;
1386                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1387                                         if (!r_glsl_permutation->compiled)
1388                                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1389                                         if (r_glsl_permutation->program)
1390                                                 break;
1391                                 }
1392                                 if (i >= SHADERPERMUTATION_COUNT)
1393                                 {
1394                                         //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext);
1395                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1396                                         qglUseProgram(0);CHECKGLERROR
1397                                         return; // no bit left to clear, entire mode is broken
1398                                 }
1399                         }
1400                 }
1401                 CHECKGLERROR
1402                 qglUseProgram(r_glsl_permutation->program);CHECKGLERROR
1403         }
1404         if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
1405         if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
1406         if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time);
1407         CHECKGLERROR
1408 }
1409
1410 void R_GLSL_Restart_f(cmd_state_t *cmd)
1411 {
1412         unsigned int i, limit;
1413         switch(vid.renderpath)
1414         {
1415         case RENDERPATH_GL32:
1416         case RENDERPATH_GLES2:
1417                 {
1418                         r_glsl_permutation_t *p;
1419                         r_glsl_permutation = NULL;
1420                         limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
1421                         for (i = 0;i < limit;i++)
1422                         {
1423                                 if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
1424                                 {
1425                                         GL_Backend_FreeProgram(p->program);
1426                                         Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
1427                                 }
1428                         }
1429                         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
1430                 }
1431                 break;
1432         }
1433 }
1434
1435 static void R_GLSL_DumpShader_f(cmd_state_t *cmd)
1436 {
1437         int i, language, mode, dupe;
1438         char *text;
1439         shadermodeinfo_t *modeinfo;
1440         qfile_t *file;
1441
1442         for (language = 0;language < SHADERLANGUAGE_COUNT;language++)
1443         {
1444                 modeinfo = shadermodeinfo[language];
1445                 for (mode = 0;mode < SHADERMODE_COUNT;mode++)
1446                 {
1447                         // don't dump the same file multiple times (most or all shaders come from the same file)
1448                         for (dupe = mode - 1;dupe >= 0;dupe--)
1449                                 if (!strcmp(modeinfo[mode].filename, modeinfo[dupe].filename))
1450                                         break;
1451                         if (dupe >= 0)
1452                                 continue;
1453                         text = modeinfo[mode].builtinstring;
1454                         if (!text)
1455                                 continue;
1456                         file = FS_OpenRealFile(modeinfo[mode].filename, "w", false);
1457                         if (file)
1458                         {
1459                                 FS_Print(file, "/* The engine may define the following macros:\n");
1460                                 FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
1461                                 for (i = 0;i < SHADERMODE_COUNT;i++)
1462                                         FS_Print(file, modeinfo[i].pretext);
1463                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1464                                         FS_Print(file, shaderpermutationinfo[i].pretext);
1465                                 FS_Print(file, "*/\n");
1466                                 FS_Print(file, text);
1467                                 FS_Close(file);
1468                                 Con_Printf("%s written\n", modeinfo[mode].filename);
1469                         }
1470                         else
1471                                 Con_Errorf("failed to write to %s\n", modeinfo[mode].filename);
1472                 }
1473         }
1474 }
1475
1476 void R_SetupShader_Generic(rtexture_t *t, qboolean usegamma, qboolean notrippy, qboolean suppresstexalpha)
1477 {
1478         dpuint64 permutation = 0;
1479         if (r_trippy.integer && !notrippy)
1480                 permutation |= SHADERPERMUTATION_TRIPPY;
1481         permutation |= SHADERPERMUTATION_VIEWTINT;
1482         if (t)
1483                 permutation |= SHADERPERMUTATION_DIFFUSE;
1484         if (usegamma && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
1485                 permutation |= SHADERPERMUTATION_GAMMARAMPS;
1486         if (suppresstexalpha)
1487                 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1488         if (vid.allowalphatocoverage)
1489                 GL_AlphaToCoverage(false);
1490         switch (vid.renderpath)
1491         {
1492         case RENDERPATH_GL32:
1493         case RENDERPATH_GLES2:
1494                 R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation);
1495                 if (r_glsl_permutation->tex_Texture_First >= 0)
1496                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First, t);
1497                 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0)
1498                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps);
1499                 break;
1500         }
1501 }
1502
1503 void R_SetupShader_Generic_NoTexture(qboolean usegamma, qboolean notrippy)
1504 {
1505         R_SetupShader_Generic(NULL, usegamma, notrippy, false);
1506 }
1507
1508 void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb, qboolean skeletal)
1509 {
1510         dpuint64 permutation = 0;
1511         if (r_trippy.integer && !notrippy)
1512                 permutation |= SHADERPERMUTATION_TRIPPY;
1513         if (depthrgb)
1514                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1515         if (skeletal)
1516                 permutation |= SHADERPERMUTATION_SKELETAL;
1517
1518         if (vid.allowalphatocoverage)
1519                 GL_AlphaToCoverage(false);
1520         switch (vid.renderpath)
1521         {
1522         case RENDERPATH_GL32:
1523         case RENDERPATH_GLES2:
1524                 R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
1525 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1526                 if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
1527 #endif
1528                 break;
1529         }
1530 }
1531
1532 #define BLENDFUNC_ALLOWS_COLORMOD      1
1533 #define BLENDFUNC_ALLOWS_FOG           2
1534 #define BLENDFUNC_ALLOWS_FOG_HACK0     4
1535 #define BLENDFUNC_ALLOWS_FOG_HACKALPHA 8
1536 #define BLENDFUNC_ALLOWS_ANYFOG        (BLENDFUNC_ALLOWS_FOG | BLENDFUNC_ALLOWS_FOG_HACK0 | BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1537 static int R_BlendFuncFlags(int src, int dst)
1538 {
1539         int r = 0;
1540
1541         // a blendfunc allows colormod if:
1542         // a) it can never keep the destination pixel invariant, or
1543         // b) it can keep the destination pixel invariant, and still can do so if colormodded
1544         // this is to prevent unintended side effects from colormod
1545
1546         // a blendfunc allows fog if:
1547         // blend(fog(src), fog(dst)) == fog(blend(src, dst))
1548         // this is to prevent unintended side effects from fog
1549
1550         // these checks are the output of fogeval.pl
1551
1552         r |= BLENDFUNC_ALLOWS_COLORMOD;
1553         if(src == GL_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1554         if(src == GL_DST_ALPHA && dst == GL_ONE_MINUS_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1555         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1556         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1557         if(src == GL_DST_COLOR && dst == GL_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1558         if(src == GL_DST_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1559         if(src == GL_DST_COLOR && dst == GL_ZERO) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1560         if(src == GL_ONE && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1561         if(src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG_HACKALPHA;
1562         if(src == GL_ONE && dst == GL_ZERO) r |= BLENDFUNC_ALLOWS_FOG;
1563         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1564         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1565         if(src == GL_ONE_MINUS_DST_COLOR && dst == GL_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1566         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1567         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1568         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1569         if(src == GL_ONE_MINUS_SRC_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1570         if(src == GL_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1571         if(src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1572         if(src == GL_ZERO && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG;
1573         if(src == GL_ZERO && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1574
1575         return r;
1576 }
1577
1578 void R_SetupShader_Surface(const float rtlightambient[3], const float rtlightdiffuse[3], const float rtlightspecular[3], rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist, void *surfacewaterplane, qboolean notrippy)
1579 {
1580         // select a permutation of the lighting shader appropriate to this
1581         // combination of texture, entity, light source, and fogging, only use the
1582         // minimum features necessary to avoid wasting rendering time in the
1583         // fragment shader on features that are not being used
1584         dpuint64 permutation = 0;
1585         unsigned int mode = 0;
1586         int blendfuncflags;
1587         texture_t *t = rsurface.texture;
1588         float m16f[16];
1589         matrix4x4_t tempmatrix;
1590         r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
1591         if (r_trippy.integer && !notrippy)
1592                 permutation |= SHADERPERMUTATION_TRIPPY;
1593         if (t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1594                 permutation |= SHADERPERMUTATION_ALPHAKILL;
1595         if (t->currentmaterialflags & MATERIALFLAG_OCCLUDE)
1596                 permutation |= SHADERPERMUTATION_OCCLUDE;
1597         if (t->r_water_waterscroll[0] && t->r_water_waterscroll[1])
1598                 permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
1599         if (rsurfacepass == RSURFPASS_BACKGROUND)
1600         {
1601                 // distorted background
1602                 if (t->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1603                 {
1604                         mode = SHADERMODE_WATER;
1605                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1606                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1607                         if((r_wateralpha.value < 1) && (t->currentmaterialflags & MATERIALFLAG_WATERALPHA))
1608                         {
1609                                 // this is the right thing to do for wateralpha
1610                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1611                                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1612                         }
1613                         else
1614                         {
1615                                 // this is the right thing to do for entity alpha
1616                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1617                                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1618                         }
1619                 }
1620                 else if (t->currentmaterialflags & MATERIALFLAG_REFRACTION)
1621                 {
1622                         mode = SHADERMODE_REFRACTION;
1623                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1624                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1625                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1626                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1627                 }
1628                 else
1629                 {
1630                         mode = SHADERMODE_GENERIC;
1631                         permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL;
1632                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1633                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1634                 }
1635                 if (vid.allowalphatocoverage)
1636                         GL_AlphaToCoverage(false);
1637         }
1638         else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
1639         {
1640                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1641                 {
1642                         switch(t->offsetmapping)
1643                         {
1644                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1645                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1646                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1647                         case OFFSETMAPPING_OFF: break;
1648                         }
1649                 }
1650                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1651                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1652                 // normalmap (deferred prepass), may use alpha test on diffuse
1653                 mode = SHADERMODE_DEFERREDGEOMETRY;
1654                 GL_BlendFunc(GL_ONE, GL_ZERO);
1655                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1656                 if (vid.allowalphatocoverage)
1657                         GL_AlphaToCoverage(false);
1658         }
1659         else if (rsurfacepass == RSURFPASS_RTLIGHT)
1660         {
1661                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1662                 {
1663                         switch(t->offsetmapping)
1664                         {
1665                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1666                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1667                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1668                         case OFFSETMAPPING_OFF: break;
1669                         }
1670                 }
1671                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1672                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1673                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1674                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1675                 // light source
1676                 mode = SHADERMODE_LIGHTSOURCE;
1677                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1678                         permutation |= SHADERPERMUTATION_CUBEFILTER;
1679                 if (VectorLength2(rtlightdiffuse) > 0)
1680                         permutation |= SHADERPERMUTATION_DIFFUSE;
1681                 if (VectorLength2(rtlightspecular) > 0)
1682                         permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1683                 if (r_refdef.fogenabled)
1684                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1685                 if (t->colormapping)
1686                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1687                 if (r_shadow_usingshadowmap2d)
1688                 {
1689                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1690                         if(r_shadow_shadowmapvsdct)
1691                                 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
1692
1693                         if (r_shadow_shadowmap2ddepthbuffer)
1694                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1695                 }
1696                 if (t->reflectmasktexture)
1697                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1698                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1699                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE);
1700                 if (vid.allowalphatocoverage)
1701                         GL_AlphaToCoverage(false);
1702         }
1703         else if (t->currentmaterialflags & MATERIALFLAG_LIGHTGRID)
1704         {
1705                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1706                 {
1707                         switch(t->offsetmapping)
1708                         {
1709                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1710                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1711                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1712                         case OFFSETMAPPING_OFF: break;
1713                         }
1714                 }
1715                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1716                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1717                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1718                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1719                 // directional model lighting
1720                 mode = SHADERMODE_LIGHTGRID;
1721                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1722                         permutation |= SHADERPERMUTATION_GLOW;
1723                 permutation |= SHADERPERMUTATION_DIFFUSE;
1724                 if (t->glosstexture || t->backgroundglosstexture)
1725                         permutation |= SHADERPERMUTATION_SPECULAR;
1726                 if (r_refdef.fogenabled)
1727                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1728                 if (t->colormapping)
1729                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1730                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1731                 {
1732                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1733                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1734
1735                         if (r_shadow_shadowmap2ddepthbuffer)
1736                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1737                 }
1738                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1739                         permutation |= SHADERPERMUTATION_REFLECTION;
1740                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1741                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1742                 if (t->reflectmasktexture)
1743                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1744                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1745                 {
1746                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1747                         if (r_shadow_bouncegrid_state.directional)
1748                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1749                 }
1750                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1751                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1752                 // when using alphatocoverage, we don't need alphakill
1753                 if (vid.allowalphatocoverage)
1754                 {
1755                         if (r_transparent_alphatocoverage.integer)
1756                         {
1757                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1758                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1759                         }
1760                         else
1761                                 GL_AlphaToCoverage(false);
1762                 }
1763         }
1764         else if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
1765         {
1766                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1767                 {
1768                         switch(t->offsetmapping)
1769                         {
1770                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1771                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1772                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1773                         case OFFSETMAPPING_OFF: break;
1774                         }
1775                 }
1776                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1777                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1778                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1779                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1780                 // directional model lighting
1781                 mode = SHADERMODE_LIGHTDIRECTION;
1782                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1783                         permutation |= SHADERPERMUTATION_GLOW;
1784                 if (VectorLength2(t->render_modellight_diffuse))
1785                         permutation |= SHADERPERMUTATION_DIFFUSE;
1786                 if (VectorLength2(t->render_modellight_specular) > 0)
1787                         permutation |= SHADERPERMUTATION_SPECULAR;
1788                 if (r_refdef.fogenabled)
1789                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1790                 if (t->colormapping)
1791                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1792                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1793                 {
1794                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1795                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1796
1797                         if (r_shadow_shadowmap2ddepthbuffer)
1798                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1799                 }
1800                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1801                         permutation |= SHADERPERMUTATION_REFLECTION;
1802                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1803                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1804                 if (t->reflectmasktexture)
1805                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1806                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1807                 {
1808                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1809                         if (r_shadow_bouncegrid_state.directional)
1810                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1811                 }
1812                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1813                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1814                 // when using alphatocoverage, we don't need alphakill
1815                 if (vid.allowalphatocoverage)
1816                 {
1817                         if (r_transparent_alphatocoverage.integer)
1818                         {
1819                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1820                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1821                         }
1822                         else
1823                                 GL_AlphaToCoverage(false);
1824                 }
1825         }
1826         else
1827         {
1828                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1829                 {
1830                         switch(t->offsetmapping)
1831                         {
1832                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1833                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1834                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1835                         case OFFSETMAPPING_OFF: break;
1836                         }
1837                 }
1838                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1839                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1840                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1841                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1842                 // lightmapped wall
1843                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1844                         permutation |= SHADERPERMUTATION_GLOW;
1845                 if (r_refdef.fogenabled)
1846                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1847                 if (t->colormapping)
1848                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1849                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1850                 {
1851                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1852                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1853
1854                         if (r_shadow_shadowmap2ddepthbuffer)
1855                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1856                 }
1857                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1858                         permutation |= SHADERPERMUTATION_REFLECTION;
1859                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1860                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1861                 if (t->reflectmasktexture)
1862                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1863                 if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
1864                 {
1865                         // deluxemapping (light direction texture)
1866                         if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace)
1867                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1868                         else
1869                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1870                         permutation |= SHADERPERMUTATION_DIFFUSE;
1871                         if (VectorLength2(t->render_lightmap_specular) > 0)
1872                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1873                 }
1874                 else if (r_glsl_deluxemapping.integer >= 2)
1875                 {
1876                         // fake deluxemapping (uniform light direction in tangentspace)
1877                         if (rsurface.uselightmaptexture)
1878                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP;
1879                         else
1880                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR;
1881                         permutation |= SHADERPERMUTATION_DIFFUSE;
1882                         if (VectorLength2(t->render_lightmap_specular) > 0)
1883                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1884                 }
1885                 else if (rsurface.uselightmaptexture)
1886                 {
1887                         // ordinary lightmapping (q1bsp, q3bsp)
1888                         mode = SHADERMODE_LIGHTMAP;
1889                 }
1890                 else
1891                 {
1892                         // ordinary vertex coloring (q3bsp)
1893                         mode = SHADERMODE_VERTEXCOLOR;
1894                 }
1895                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1896                 {
1897                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1898                         if (r_shadow_bouncegrid_state.directional)
1899                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1900                 }
1901                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1902                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1903                 // when using alphatocoverage, we don't need alphakill
1904                 if (vid.allowalphatocoverage)
1905                 {
1906                         if (r_transparent_alphatocoverage.integer)
1907                         {
1908                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1909                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1910                         }
1911                         else
1912                                 GL_AlphaToCoverage(false);
1913                 }
1914         }
1915         if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG))
1916                 permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE);
1917         if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1918                 permutation |= SHADERPERMUTATION_FOGALPHAHACK;
1919         switch(vid.renderpath)
1920         {
1921         case RENDERPATH_GL32:
1922         case RENDERPATH_GLES2:
1923                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | (rsurface.modellightmapcolor4f ? BATCHNEED_ARRAY_VERTEXCOLOR : 0) | BATCHNEED_ARRAY_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_ARRAY_LIGHTMAP : 0) | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
1924                 RSurf_UploadBuffersForBatch();
1925                 // this has to be after RSurf_PrepareVerticesForBatch
1926                 if (rsurface.batchskeletaltransform3x4buffer)
1927                         permutation |= SHADERPERMUTATION_SKELETAL;
1928                 R_SetupShader_SetPermutationGLSL(mode, permutation);
1929 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1930                 if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
1931 #endif
1932                 if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
1933                 if (mode == SHADERMODE_LIGHTSOURCE)
1934                 {
1935                         if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
1936                         if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1937                         if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1938                         if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
1939                         if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
1940                         if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
1941         
1942                         // additive passes are only darkened by fog, not tinted
1943                         if (r_glsl_permutation->loc_FogColor >= 0)
1944                                 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1945                         if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, t->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
1946                 }
1947                 else
1948                 {
1949                         if (mode == SHADERMODE_FLATCOLOR)
1950                         {
1951                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
1952                         }
1953                         else if (mode == SHADERMODE_LIGHTGRID)
1954                         {
1955                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_lightmap_ambient[0], t->render_lightmap_ambient[1], t->render_lightmap_ambient[2]);
1956                                 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_lightmap_diffuse[0], t->render_lightmap_diffuse[1], t->render_lightmap_diffuse[2]);
1957                                 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_lightmap_specular[0], t->render_lightmap_specular[1], t->render_lightmap_specular[2]);
1958                                 // other LightGrid uniforms handled below
1959                         }
1960                         else if (mode == SHADERMODE_LIGHTDIRECTION)
1961                         {
1962                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
1963                                 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_modellight_diffuse[0], t->render_modellight_diffuse[1], t->render_modellight_diffuse[2]);
1964                                 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_modellight_specular[0], t->render_modellight_specular[1], t->render_modellight_specular[2]);
1965                                 if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, t->render_rtlight_diffuse[0], t->render_rtlight_diffuse[1], t->render_rtlight_diffuse[2]);
1966                                 if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, t->render_rtlight_specular[0], t->render_rtlight_specular[1], t->render_rtlight_specular[2]);
1967                                 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1968                                 if (r_glsl_permutation->loc_LightDir >= 0) qglUniform3f(r_glsl_permutation->loc_LightDir, t->render_modellight_lightdir[0], t->render_modellight_lightdir[1], t->render_modellight_lightdir[2]);
1969                         }
1970                         else
1971                         {
1972                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_lightmap_ambient[0], t->render_lightmap_ambient[1], t->render_lightmap_ambient[2]);
1973                                 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_lightmap_diffuse[0], t->render_lightmap_diffuse[1], t->render_lightmap_diffuse[2]);
1974                                 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_lightmap_specular[0], t->render_lightmap_specular[1], t->render_lightmap_specular[2]);
1975                                 if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, t->render_rtlight_diffuse[0], t->render_rtlight_diffuse[1], t->render_rtlight_diffuse[2]);
1976                                 if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, t->render_rtlight_specular[0], t->render_rtlight_specular[1], t->render_rtlight_specular[2]);
1977                         }
1978                         // additive passes are only darkened by fog, not tinted
1979                         if (r_glsl_permutation->loc_FogColor >= 0)
1980                         {
1981                                 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
1982                                         qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1983                                 else
1984                                         qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1985                         }
1986                         if (r_glsl_permutation->loc_DistortScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_DistortScaleRefractReflect, r_water_refractdistort.value * t->refractfactor, r_water_refractdistort.value * t->refractfactor, r_water_reflectdistort.value * t->reflectfactor, r_water_reflectdistort.value * t->reflectfactor);
1987                         if (r_glsl_permutation->loc_ScreenScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenScaleRefractReflect, r_fb.water.screenscale[0], r_fb.water.screenscale[1], r_fb.water.screenscale[0], r_fb.water.screenscale[1]);
1988                         if (r_glsl_permutation->loc_ScreenCenterRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenCenterRefractReflect, r_fb.water.screencenter[0], r_fb.water.screencenter[1], r_fb.water.screencenter[0], r_fb.water.screencenter[1]);
1989                         if (r_glsl_permutation->loc_RefractColor >= 0) qglUniform4f(r_glsl_permutation->loc_RefractColor, t->refractcolor4f[0], t->refractcolor4f[1], t->refractcolor4f[2], t->refractcolor4f[3] * t->currentalpha);
1990                         if (r_glsl_permutation->loc_ReflectColor >= 0) qglUniform4f(r_glsl_permutation->loc_ReflectColor, t->reflectcolor4f[0], t->reflectcolor4f[1], t->reflectcolor4f[2], t->reflectcolor4f[3] * t->currentalpha);
1991                         if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, t->reflectmax - t->reflectmin);
1992                         if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, t->reflectmin);
1993                         if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, t->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
1994                         if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
1995                 }
1996                 if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
1997                 if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
1998                 if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
1999                 if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
2000                 {
2001                         if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_modelshadowmap_texturescale[0], r_shadow_modelshadowmap_texturescale[1], r_shadow_modelshadowmap_texturescale[2], r_shadow_modelshadowmap_texturescale[3]);
2002                         if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_modelshadowmap_parameters[0], r_shadow_modelshadowmap_parameters[1], r_shadow_modelshadowmap_parameters[2], r_shadow_modelshadowmap_parameters[3]);
2003                 }
2004                 else
2005                 {
2006                         if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
2007                         if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
2008                 }
2009
2010                 if (r_glsl_permutation->loc_Color_Glow >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Glow, t->render_glowmod[0], t->render_glowmod[1], t->render_glowmod[2]);
2011                 if (r_glsl_permutation->loc_Alpha >= 0) qglUniform1f(r_glsl_permutation->loc_Alpha, t->currentalpha * ((t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? t->r_water_wateralpha : 1));
2012                 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
2013                 if (r_glsl_permutation->loc_Color_Pants >= 0)
2014                 {
2015                         if (t->pantstexture)
2016                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
2017                         else
2018                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
2019                 }
2020                 if (r_glsl_permutation->loc_Color_Shirt >= 0)
2021                 {
2022                         if (t->shirttexture)
2023                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
2024                         else
2025                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
2026                 }
2027                 if (r_glsl_permutation->loc_FogPlane >= 0) qglUniform4f(r_glsl_permutation->loc_FogPlane, rsurface.fogplane[0], rsurface.fogplane[1], rsurface.fogplane[2], rsurface.fogplane[3]);
2028                 if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
2029                 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
2030                 if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
2031                 if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps,
2032                                 r_glsl_offsetmapping_scale.value*t->offsetscale,
2033                                 max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2034                                 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2035                                 max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
2036                         );
2037                 if (r_glsl_permutation->loc_OffsetMapping_LodDistance >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer * r_refdef.view.quality);
2038                 if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, t->offsetbias);
2039                 if (r_glsl_permutation->loc_ScreenToDepth >= 0) qglUniform2f(r_glsl_permutation->loc_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
2040                 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
2041                 if (r_glsl_permutation->loc_BounceGridMatrix >= 0) {Matrix4x4_Concat(&tempmatrix, &r_shadow_bouncegrid_state.matrix, &rsurface.matrix);Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BounceGridMatrix, 1, false, m16f);}
2042                 if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
2043                 if (r_glsl_permutation->loc_LightGridMatrix >= 0 && r_refdef.scene.worldmodel)
2044                 {
2045                         float m9f[9];
2046                         Matrix4x4_Concat(&tempmatrix, &r_refdef.scene.worldmodel->brushq3.lightgridworldtotexturematrix, &rsurface.matrix);
2047                         Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);
2048                         qglUniformMatrix4fv(r_glsl_permutation->loc_LightGridMatrix, 1, false, m16f);
2049                         Matrix4x4_Normalize3(&tempmatrix, &rsurface.matrix);
2050                         Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);
2051                         m9f[0] = m16f[0];m9f[1] = m16f[1];m9f[2] = m16f[2];
2052                         m9f[3] = m16f[4];m9f[4] = m16f[5];m9f[5] = m16f[6];
2053                         m9f[6] = m16f[8];m9f[7] = m16f[9];m9f[8] = m16f[10];
2054                         qglUniformMatrix3fv(r_glsl_permutation->loc_LightGridNormalMatrix, 1, false, m9f);
2055                 }
2056
2057                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First            , r_texture_white                                     );
2058                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second           , r_texture_white                                     );
2059                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps       , r_texture_gammaramps                                );
2060                 if (r_glsl_permutation->tex_Texture_Normal          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal           , t->nmaptexture                       );
2061                 if (r_glsl_permutation->tex_Texture_Color           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color            , t->basetexture                       );
2062                 if (r_glsl_permutation->tex_Texture_Gloss           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss            , t->glosstexture                      );
2063                 if (r_glsl_permutation->tex_Texture_Glow            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow             , t->glowtexture                       );
2064                 if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal  , t->backgroundnmaptexture             );
2065                 if (r_glsl_permutation->tex_Texture_SecondaryColor  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor   , t->backgroundbasetexture             );
2066                 if (r_glsl_permutation->tex_Texture_SecondaryGloss  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss   , t->backgroundglosstexture            );
2067                 if (r_glsl_permutation->tex_Texture_SecondaryGlow   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow    , t->backgroundglowtexture             );
2068                 if (r_glsl_permutation->tex_Texture_Pants           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants            , t->pantstexture                      );
2069                 if (r_glsl_permutation->tex_Texture_Shirt           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt            , t->shirttexture                      );
2070                 if (r_glsl_permutation->tex_Texture_ReflectMask     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask      , t->reflectmasktexture                );
2071                 if (r_glsl_permutation->tex_Texture_ReflectCube     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube      , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
2072                 if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture                          );
2073                 if (r_glsl_permutation->tex_Texture_FogMask         >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask          , r_texture_fogattenuation                            );
2074                 if (r_glsl_permutation->tex_Texture_Lightmap        >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap         , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
2075                 if (r_glsl_permutation->tex_Texture_Deluxemap       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Deluxemap        , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap);
2076                 if (r_glsl_permutation->tex_Texture_Attenuation     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation      , r_shadow_attenuationgradienttexture                 );
2077                 if (rsurfacepass == RSURFPASS_BACKGROUND)
2078                 {
2079                         if (r_glsl_permutation->tex_Texture_Refraction  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Refraction        , waterplane->rt_refraction ? waterplane->rt_refraction->colortexture[0] : r_texture_black);
2080                         if (r_glsl_permutation->tex_Texture_First       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First             , waterplane->rt_camera ? waterplane->rt_camera->colortexture[0] : r_texture_black);
2081                         if (r_glsl_permutation->tex_Texture_Reflection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection        , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
2082                 }
2083                 else
2084                 {
2085                         if (r_glsl_permutation->tex_Texture_Reflection >= 0 && waterplane) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection        , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
2086                 }
2087                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap   , r_shadow_prepassgeometrynormalmaptexture            );
2088                 if (r_glsl_permutation->tex_Texture_ScreenDiffuse   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse     , r_shadow_prepasslightingdiffusetexture              );
2089                 if (r_glsl_permutation->tex_Texture_ScreenSpecular  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular    , r_shadow_prepasslightingspeculartexture             );
2090                 if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
2091                 {
2092                         if (r_glsl_permutation->tex_Texture_ShadowMap2D     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture                           );
2093                         if (rsurface.rtlight)
2094                         {
2095                                 if (r_glsl_permutation->tex_Texture_Cube            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube              , rsurface.rtlight->currentcubemap                    );
2096                                 if (r_glsl_permutation->tex_Texture_CubeProjection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection    , r_shadow_shadowmapvsdcttexture                      );
2097                         }
2098                 }
2099                 if (r_glsl_permutation->tex_Texture_BounceGrid  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
2100                 if (r_glsl_permutation->tex_Texture_LightGrid   >= 0 && r_refdef.scene.worldmodel) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_LightGrid, r_refdef.scene.worldmodel->brushq3.lightgridtexture);
2101                 CHECKGLERROR
2102                 break;
2103         }
2104 }
2105
2106 void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
2107 {
2108         // select a permutation of the lighting shader appropriate to this
2109         // combination of texture, entity, light source, and fogging, only use the
2110         // minimum features necessary to avoid wasting rendering time in the
2111         // fragment shader on features that are not being used
2112         dpuint64 permutation = 0;
2113         unsigned int mode = 0;
2114         const float *lightcolorbase = rtlight->currentcolor;
2115         float ambientscale = rtlight->ambientscale;
2116         float diffusescale = rtlight->diffusescale;
2117         float specularscale = rtlight->specularscale;
2118         // this is the location of the light in view space
2119         vec3_t viewlightorigin;
2120         // this transforms from view space (camera) to light space (cubemap)
2121         matrix4x4_t viewtolight;
2122         matrix4x4_t lighttoview;
2123         float viewtolight16f[16];
2124         // light source
2125         mode = SHADERMODE_DEFERREDLIGHTSOURCE;
2126         if (rtlight->currentcubemap != r_texture_whitecube)
2127                 permutation |= SHADERPERMUTATION_CUBEFILTER;
2128         if (diffusescale > 0)
2129                 permutation |= SHADERPERMUTATION_DIFFUSE;
2130         if (specularscale > 0 && r_shadow_gloss.integer > 0)
2131                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2132         if (r_shadow_usingshadowmap2d)
2133         {
2134                 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
2135                 if (r_shadow_shadowmapvsdct)
2136                         permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
2137
2138                 if (r_shadow_shadowmap2ddepthbuffer)
2139                         permutation |= SHADERPERMUTATION_DEPTHRGB;
2140         }
2141         if (vid.allowalphatocoverage)
2142                 GL_AlphaToCoverage(false);
2143         Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
2144         Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
2145         Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
2146         Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
2147         switch(vid.renderpath)
2148         {
2149         case RENDERPATH_GL32:
2150         case RENDERPATH_GLES2:
2151                 R_SetupShader_SetPermutationGLSL(mode, permutation);
2152                 if (r_glsl_permutation->loc_LightPosition             >= 0) qglUniform3f(       r_glsl_permutation->loc_LightPosition            , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
2153                 if (r_glsl_permutation->loc_ViewToLight               >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight              , 1, false, viewtolight16f);
2154                 if (r_glsl_permutation->loc_DeferredColor_Ambient     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Ambient    , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
2155                 if (r_glsl_permutation->loc_DeferredColor_Diffuse     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
2156                 if (r_glsl_permutation->loc_DeferredColor_Specular    >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Specular   , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
2157                 if (r_glsl_permutation->loc_ShadowMap_TextureScale    >= 0) qglUniform4f(       r_glsl_permutation->loc_ShadowMap_TextureScale   , r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
2158                 if (r_glsl_permutation->loc_ShadowMap_Parameters      >= 0) qglUniform4f(       r_glsl_permutation->loc_ShadowMap_Parameters     , r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
2159                 if (r_glsl_permutation->loc_SpecularPower             >= 0) qglUniform1f(       r_glsl_permutation->loc_SpecularPower            , (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
2160                 if (r_glsl_permutation->loc_ScreenToDepth             >= 0) qglUniform2f(       r_glsl_permutation->loc_ScreenToDepth            , r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
2161                 if (r_glsl_permutation->loc_PixelToScreenTexCoord     >= 0) qglUniform2f(       r_glsl_permutation->loc_PixelToScreenTexCoord    , 1.0f/vid.width, 1.0f/vid.height);
2162
2163                 if (r_glsl_permutation->tex_Texture_Attenuation       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation        , r_shadow_attenuationgradienttexture                 );
2164                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap    , r_shadow_prepassgeometrynormalmaptexture            );
2165                 if (r_glsl_permutation->tex_Texture_Cube              >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube               , rsurface.rtlight->currentcubemap                    );
2166                 if (r_glsl_permutation->tex_Texture_ShadowMap2D       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D        , r_shadow_shadowmap2ddepthtexture                    );
2167                 if (r_glsl_permutation->tex_Texture_CubeProjection    >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection     , r_shadow_shadowmapvsdcttexture                      );
2168                 break;
2169         }
2170 }
2171
2172 #define SKINFRAME_HASH 1024
2173
2174 typedef struct
2175 {
2176         unsigned int loadsequence; // incremented each level change
2177         memexpandablearray_t array;
2178         skinframe_t *hash[SKINFRAME_HASH];
2179 }
2180 r_skinframe_t;
2181 r_skinframe_t r_skinframe;
2182
2183 void R_SkinFrame_PrepareForPurge(void)
2184 {
2185         r_skinframe.loadsequence++;
2186         // wrap it without hitting zero
2187         if (r_skinframe.loadsequence >= 200)
2188                 r_skinframe.loadsequence = 1;
2189 }
2190
2191 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
2192 {
2193         if (!skinframe)
2194                 return;
2195         // mark the skinframe as used for the purging code
2196         skinframe->loadsequence = r_skinframe.loadsequence;
2197 }
2198
2199 void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
2200 {
2201         if (s == NULL)
2202                 return;
2203         if (s->merged == s->base)
2204                 s->merged = NULL;
2205         R_PurgeTexture(s->stain); s->stain = NULL;
2206         R_PurgeTexture(s->merged); s->merged = NULL;
2207         R_PurgeTexture(s->base); s->base = NULL;
2208         R_PurgeTexture(s->pants); s->pants = NULL;
2209         R_PurgeTexture(s->shirt); s->shirt = NULL;
2210         R_PurgeTexture(s->nmap); s->nmap = NULL;
2211         R_PurgeTexture(s->gloss); s->gloss = NULL;
2212         R_PurgeTexture(s->glow); s->glow = NULL;
2213         R_PurgeTexture(s->fog); s->fog = NULL;
2214         R_PurgeTexture(s->reflect); s->reflect = NULL;
2215         s->loadsequence = 0;
2216 }
2217
2218 void R_SkinFrame_Purge(void)
2219 {
2220         int i;
2221         skinframe_t *s;
2222         for (i = 0;i < SKINFRAME_HASH;i++)
2223         {
2224                 for (s = r_skinframe.hash[i];s;s = s->next)
2225                 {
2226                         if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
2227                                 R_SkinFrame_PurgeSkinFrame(s);
2228                 }
2229         }
2230 }
2231
2232 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
2233         skinframe_t *item;
2234         char basename[MAX_QPATH];
2235
2236         Image_StripImageExtension(name, basename, sizeof(basename));
2237
2238         if( last == NULL ) {
2239                 int hashindex;
2240                 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2241                 item = r_skinframe.hash[hashindex];
2242         } else {
2243                 item = last->next;
2244         }
2245
2246         // linearly search through the hash bucket
2247         for( ; item ; item = item->next ) {
2248                 if( !strcmp( item->basename, basename ) ) {
2249                         return item;
2250                 }
2251         }
2252         return NULL;
2253 }
2254
2255 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add)
2256 {
2257         skinframe_t *item;
2258         int compareflags = textureflags & TEXF_IMPORTANTBITS;
2259         int hashindex;
2260         char basename[MAX_QPATH];
2261
2262         Image_StripImageExtension(name, basename, sizeof(basename));
2263
2264         hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2265         for (item = r_skinframe.hash[hashindex];item;item = item->next)
2266                 if (!strcmp(item->basename, basename) &&
2267                         item->textureflags == compareflags &&
2268                         item->comparewidth == comparewidth &&
2269                         item->compareheight == compareheight &&
2270                         item->comparecrc == comparecrc)
2271                         break;
2272
2273         if (!item)
2274         {
2275                 if (!add)
2276                         return NULL;
2277                 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
2278                 memset(item, 0, sizeof(*item));
2279                 strlcpy(item->basename, basename, sizeof(item->basename));
2280                 item->textureflags = compareflags;
2281                 item->comparewidth = comparewidth;
2282                 item->compareheight = compareheight;
2283                 item->comparecrc = comparecrc;
2284                 item->next = r_skinframe.hash[hashindex];
2285                 r_skinframe.hash[hashindex] = item;
2286         }
2287         else if (textureflags & TEXF_FORCE_RELOAD)
2288                 R_SkinFrame_PurgeSkinFrame(item);
2289
2290         R_SkinFrame_MarkUsed(item);
2291         return item;
2292 }
2293
2294 #define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
2295         { \
2296                 unsigned long long avgcolor[5], wsum; \
2297                 int pix, comp, w; \
2298                 avgcolor[0] = 0; \
2299                 avgcolor[1] = 0; \
2300                 avgcolor[2] = 0; \
2301                 avgcolor[3] = 0; \
2302                 avgcolor[4] = 0; \
2303                 wsum = 0; \
2304                 for(pix = 0; pix < cnt; ++pix) \
2305                 { \
2306                         w = 0; \
2307                         for(comp = 0; comp < 3; ++comp) \
2308                                 w += getpixel; \
2309                         if(w) /* ignore perfectly black pixels because that is better for model skins */ \
2310                         { \
2311                                 ++wsum; \
2312                                 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2313                                 w = getpixel; \
2314                                 for(comp = 0; comp < 3; ++comp) \
2315                                         avgcolor[comp] += getpixel * w; \
2316                                 avgcolor[3] += w; \
2317                         } \
2318                         /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2319                         avgcolor[4] += getpixel; \
2320                 } \
2321                 if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
2322                         avgcolor[3] = 1; \
2323                 skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
2324                 skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
2325                 skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
2326                 skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
2327         }
2328
2329 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2330 {
2331         skinframe_t *skinframe;
2332
2333         if (cls.state == ca_dedicated)
2334                 return NULL;
2335
2336         // return an existing skinframe if already loaded
2337         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
2338         if (skinframe && skinframe->base)
2339                 return skinframe;
2340
2341         // if the skinframe doesn't exist this will create it
2342         return R_SkinFrame_LoadExternal_SkinFrame(skinframe, name, textureflags, complain, fallbacknotexture);
2343 }
2344
2345 extern cvar_t gl_picmip;
2346 skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2347 {
2348         int j;
2349         unsigned char *pixels;
2350         unsigned char *bumppixels;
2351         unsigned char *basepixels = NULL;
2352         int basepixels_width = 0;
2353         int basepixels_height = 0;
2354         rtexture_t *ddsbase = NULL;
2355         qboolean ddshasalpha = false;
2356         float ddsavgcolor[4];
2357         char basename[MAX_QPATH];
2358         int miplevel = R_PicmipForFlags(textureflags);
2359         int savemiplevel = miplevel;
2360         int mymiplevel;
2361         char vabuf[1024];
2362
2363         if (cls.state == ca_dedicated)
2364                 return NULL;
2365
2366         Image_StripImageExtension(name, basename, sizeof(basename));
2367
2368         // check for DDS texture file first
2369         if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2370         {
2371                 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2372                 if (basepixels == NULL && fallbacknotexture)
2373                         basepixels = Image_GenerateNoTexture();
2374                 if (basepixels == NULL)
2375                         return NULL;
2376         }
2377
2378         // FIXME handle miplevel
2379
2380         if (developer_loading.integer)
2381                 Con_Printf("loading skin \"%s\"\n", name);
2382
2383         // we've got some pixels to store, so really allocate this new texture now
2384         if (!skinframe)
2385                 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2386         textureflags &= ~TEXF_FORCE_RELOAD;
2387         skinframe->stain = NULL;
2388         skinframe->merged = NULL;
2389         skinframe->base = NULL;
2390         skinframe->pants = NULL;
2391         skinframe->shirt = NULL;
2392         skinframe->nmap = NULL;
2393         skinframe->gloss = NULL;
2394         skinframe->glow = NULL;
2395         skinframe->fog = NULL;
2396         skinframe->reflect = NULL;
2397         skinframe->hasalpha = false;
2398         // we could store the q2animname here too
2399
2400         if (ddsbase)
2401         {
2402                 skinframe->base = ddsbase;
2403                 skinframe->hasalpha = ddshasalpha;
2404                 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2405                 if (r_loadfog && skinframe->hasalpha)
2406                         skinframe->fog = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), false, textureflags | TEXF_ALPHA, NULL, NULL, miplevel, true);
2407                 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2408         }
2409         else
2410         {
2411                 basepixels_width = image_width;
2412                 basepixels_height = image_height;
2413                 skinframe->base = R_LoadTexture2D (r_main_texturepool, skinframe->basename, basepixels_width, basepixels_height, basepixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL);
2414                 if (textureflags & TEXF_ALPHA)
2415                 {
2416                         for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2417                         {
2418                                 if (basepixels[j] < 255)
2419                                 {
2420                                         skinframe->hasalpha = true;
2421                                         break;
2422                                 }
2423                         }
2424                         if (r_loadfog && skinframe->hasalpha)
2425                         {
2426                                 // has transparent pixels
2427                                 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2428                                 for (j = 0;j < image_width * image_height * 4;j += 4)
2429                                 {
2430                                         pixels[j+0] = 255;
2431                                         pixels[j+1] = 255;
2432                                         pixels[j+2] = 255;
2433                                         pixels[j+3] = basepixels[j+3];
2434                                 }
2435                                 skinframe->fog = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_mask", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL);
2436                                 Mem_Free(pixels);
2437                         }
2438                 }
2439                 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2440 #ifndef USE_GLES2
2441                 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2442                 if (r_savedds && skinframe->base)
2443                         R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2444                 if (r_savedds && skinframe->fog)
2445                         R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2446 #endif
2447         }
2448
2449         if (r_loaddds)
2450         {
2451                 mymiplevel = savemiplevel;
2452                 if (r_loadnormalmap)
2453                         skinframe->nmap = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), false, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), NULL, NULL, mymiplevel, true);
2454                 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2455                 if (r_loadgloss)
2456                         skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2457                 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2458                 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2459                 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2460         }
2461
2462         // _norm is the name used by tenebrae and has been adopted as standard
2463         if (r_loadnormalmap && skinframe->nmap == NULL)
2464         {
2465                 mymiplevel = savemiplevel;
2466                 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2467                 {
2468                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2469                         Mem_Free(pixels);
2470                         pixels = NULL;
2471                 }
2472                 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2473                 {
2474                         pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2475                         Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2476                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2477                         Mem_Free(pixels);
2478                         Mem_Free(bumppixels);
2479                 }
2480                 else if (r_shadow_bumpscale_basetexture.value > 0)
2481                 {
2482                         pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2483                         Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2484                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), basepixels_width, basepixels_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2485                         Mem_Free(pixels);
2486                 }
2487 #ifndef USE_GLES2
2488                 if (r_savedds && skinframe->nmap)
2489                         R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2490 #endif
2491         }
2492
2493         // _luma is supported only for tenebrae compatibility
2494         // _blend and .blend are supported only for Q3 & QL compatibility, this hack can be removed if better Q3 shader support is implemented
2495         // _glow is the preferred name
2496         mymiplevel = savemiplevel;
2497         if (skinframe->glow == NULL && ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s.blend", skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_blend", skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_luma", skinframe->basename), false, false, false, &mymiplevel))))
2498         {
2499                 skinframe->glow = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_glow.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2500 #ifndef USE_GLES2
2501                 if (r_savedds && skinframe->glow)
2502                         R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2503 #endif
2504                 Mem_Free(pixels);pixels = NULL;
2505         }
2506
2507         mymiplevel = savemiplevel;
2508         if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2509         {
2510                 skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (gl_texturecompression_gloss.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2511 #ifndef USE_GLES2
2512                 if (r_savedds && skinframe->gloss)
2513                         R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2514 #endif
2515                 Mem_Free(pixels);
2516                 pixels = NULL;
2517         }
2518
2519         mymiplevel = savemiplevel;
2520         if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2521         {
2522                 skinframe->pants = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2523 #ifndef USE_GLES2
2524                 if (r_savedds && skinframe->pants)
2525                         R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2526 #endif
2527                 Mem_Free(pixels);
2528                 pixels = NULL;
2529         }
2530
2531         mymiplevel = savemiplevel;
2532         if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2533         {
2534                 skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2535 #ifndef USE_GLES2
2536                 if (r_savedds && skinframe->shirt)
2537                         R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2538 #endif
2539                 Mem_Free(pixels);
2540                 pixels = NULL;
2541         }
2542
2543         mymiplevel = savemiplevel;
2544         if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2545         {
2546                 skinframe->reflect = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_reflectmask.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2547 #ifndef USE_GLES2
2548                 if (r_savedds && skinframe->reflect)
2549                         R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2550 #endif
2551                 Mem_Free(pixels);
2552                 pixels = NULL;
2553         }
2554
2555         if (basepixels)
2556                 Mem_Free(basepixels);
2557
2558         return skinframe;
2559 }
2560
2561 skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, int comparewidth, int compareheight, int comparecrc, qboolean sRGB)
2562 {
2563         int i;
2564         skinframe_t *skinframe;
2565         char vabuf[1024];
2566
2567         if (cls.state == ca_dedicated)
2568                 return NULL;
2569
2570         // if already loaded just return it, otherwise make a new skinframe
2571         skinframe = R_SkinFrame_Find(name, textureflags, comparewidth, compareheight, comparecrc, true);
2572         if (skinframe->base)
2573                 return skinframe;
2574         textureflags &= ~TEXF_FORCE_RELOAD;
2575
2576         skinframe->stain = NULL;
2577         skinframe->merged = NULL;
2578         skinframe->base = NULL;
2579         skinframe->pants = NULL;
2580         skinframe->shirt = NULL;
2581         skinframe->nmap = NULL;
2582         skinframe->gloss = NULL;
2583         skinframe->glow = NULL;
2584         skinframe->fog = NULL;
2585         skinframe->reflect = NULL;
2586         skinframe->hasalpha = false;
2587
2588         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2589         if (!skindata)
2590                 return NULL;
2591
2592         if (developer_loading.integer)
2593                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2594
2595         if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2596         {
2597                 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2598                 unsigned char *b = a + width * height * 4;
2599                 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2600                 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, b, TEXTYPE_BGRA, (textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
2601                 Mem_Free(a);
2602         }
2603         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2604         if (textureflags & TEXF_ALPHA)
2605         {
2606                 for (i = 3;i < width * height * 4;i += 4)
2607                 {
2608                         if (skindata[i] < 255)
2609                         {
2610                                 skinframe->hasalpha = true;
2611                                 break;
2612                         }
2613                 }
2614                 if (r_loadfog && skinframe->hasalpha)
2615                 {
2616                         unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2617                         memcpy(fogpixels, skindata, width * height * 4);
2618                         for (i = 0;i < width * height * 4;i += 4)
2619                                 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2620                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2621                         Mem_Free(fogpixels);
2622                 }
2623         }
2624
2625         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2626         //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2627
2628         return skinframe;
2629 }
2630
2631 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2632 {
2633         int i;
2634         int featuresmask;
2635         skinframe_t *skinframe;
2636
2637         if (cls.state == ca_dedicated)
2638                 return NULL;
2639
2640         // if already loaded just return it, otherwise make a new skinframe
2641         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2642         if (skinframe->base)
2643                 return skinframe;
2644         //textureflags &= ~TEXF_FORCE_RELOAD;
2645
2646         skinframe->stain = NULL;
2647         skinframe->merged = NULL;
2648         skinframe->base = NULL;
2649         skinframe->pants = NULL;
2650         skinframe->shirt = NULL;
2651         skinframe->nmap = NULL;
2652         skinframe->gloss = NULL;
2653         skinframe->glow = NULL;
2654         skinframe->fog = NULL;
2655         skinframe->reflect = NULL;
2656         skinframe->hasalpha = false;
2657
2658         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2659         if (!skindata)
2660                 return NULL;
2661
2662         if (developer_loading.integer)
2663                 Con_Printf("loading quake skin \"%s\"\n", name);
2664
2665         // we actually don't upload anything until the first use, because mdl skins frequently go unused, and are almost never used in both modes (colormapped and non-colormapped)
2666         skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2667         memcpy(skinframe->qpixels, skindata, width*height);
2668         skinframe->qwidth = width;
2669         skinframe->qheight = height;
2670
2671         featuresmask = 0;
2672         for (i = 0;i < width * height;i++)
2673                 featuresmask |= palette_featureflags[skindata[i]];
2674
2675         skinframe->hasalpha = false;
2676         // fence textures
2677         if (name[0] == '{')
2678                 skinframe->hasalpha = true;
2679         skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2680         skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2681         skinframe->qgeneratemerged = true;
2682         skinframe->qgeneratebase = skinframe->qhascolormapping;
2683         skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2684
2685         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2686         //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2687
2688         return skinframe;
2689 }
2690
2691 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboolean colormapped)
2692 {
2693         int width;
2694         int height;
2695         unsigned char *skindata;
2696         char vabuf[1024];
2697
2698         if (!skinframe->qpixels)
2699                 return;
2700
2701         if (!skinframe->qhascolormapping)
2702                 colormapped = false;
2703
2704         if (colormapped)
2705         {
2706                 if (!skinframe->qgeneratebase)
2707                         return;
2708         }
2709         else
2710         {
2711                 if (!skinframe->qgeneratemerged)
2712                         return;
2713         }
2714
2715         width = skinframe->qwidth;
2716         height = skinframe->qheight;
2717         skindata = skinframe->qpixels;
2718
2719         if (skinframe->qgeneratenmap)
2720         {
2721                 unsigned char *a, *b;
2722                 skinframe->qgeneratenmap = false;
2723                 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2724                 b = a + width * height * 4;
2725                 // use either a custom palette or the quake palette
2726                 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2727                 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2728                 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, b, TEXTYPE_BGRA, (skinframe->textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
2729                 Mem_Free(a);
2730         }
2731
2732         if (skinframe->qgenerateglow)
2733         {
2734                 skinframe->qgenerateglow = false;
2735                 if (skinframe->hasalpha) // fence textures
2736                         skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags | TEXF_ALPHA, -1, palette_bgra_onlyfullbrights_transparent); // glow
2737                 else
2738                         skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_onlyfullbrights); // glow
2739         }
2740
2741         if (colormapped)
2742         {
2743                 skinframe->qgeneratebase = false;
2744                 skinframe->base  = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nospecial", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nocolormapnofullbrights : palette_bgra_nocolormap);
2745                 skinframe->pants = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_pantsaswhite);
2746                 skinframe->shirt = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_shirtaswhite);
2747         }
2748         else
2749         {
2750                 skinframe->qgeneratemerged = false;
2751                 if (skinframe->hasalpha) // fence textures
2752                         skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags | TEXF_ALPHA, -1, skinframe->glow ? palette_bgra_nofullbrights_transparent : palette_bgra_transparent);
2753                 else
2754                         skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nofullbrights : palette_bgra_complete);
2755         }
2756
2757         if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2758         {
2759                 Mem_Free(skinframe->qpixels);
2760                 skinframe->qpixels = NULL;
2761         }
2762 }
2763
2764 skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, const unsigned char *skindata, int width, int height, const unsigned int *palette, const unsigned int *alphapalette)
2765 {
2766         int i;
2767         skinframe_t *skinframe;
2768         char vabuf[1024];
2769
2770         if (cls.state == ca_dedicated)
2771                 return NULL;
2772
2773         // if already loaded just return it, otherwise make a new skinframe
2774         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2775         if (skinframe->base)
2776                 return skinframe;
2777         textureflags &= ~TEXF_FORCE_RELOAD;
2778
2779         skinframe->stain = NULL;
2780         skinframe->merged = NULL;
2781         skinframe->base = NULL;
2782         skinframe->pants = NULL;
2783         skinframe->shirt = NULL;
2784         skinframe->nmap = NULL;
2785         skinframe->gloss = NULL;
2786         skinframe->glow = NULL;
2787         skinframe->fog = NULL;
2788         skinframe->reflect = NULL;
2789         skinframe->hasalpha = false;
2790
2791         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2792         if (!skindata)
2793                 return NULL;
2794
2795         if (developer_loading.integer)
2796                 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2797
2798         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2799         if ((textureflags & TEXF_ALPHA) && alphapalette)
2800         {
2801                 for (i = 0;i < width * height;i++)
2802                 {
2803                         if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2804                         {
2805                                 skinframe->hasalpha = true;
2806                                 break;
2807                         }
2808                 }
2809                 if (r_loadfog && skinframe->hasalpha)
2810                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2811         }
2812
2813         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2814         //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2815
2816         return skinframe;
2817 }
2818
2819 skinframe_t *R_SkinFrame_LoadMissing(void)
2820 {
2821         skinframe_t *skinframe;
2822
2823         if (cls.state == ca_dedicated)
2824                 return NULL;
2825
2826         skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2827         skinframe->stain = NULL;
2828         skinframe->merged = NULL;
2829         skinframe->base = NULL;
2830         skinframe->pants = NULL;
2831         skinframe->shirt = NULL;
2832         skinframe->nmap = NULL;
2833         skinframe->gloss = NULL;
2834         skinframe->glow = NULL;
2835         skinframe->fog = NULL;
2836         skinframe->reflect = NULL;
2837         skinframe->hasalpha = false;
2838
2839         skinframe->avgcolor[0] = rand() / RAND_MAX;
2840         skinframe->avgcolor[1] = rand() / RAND_MAX;
2841         skinframe->avgcolor[2] = rand() / RAND_MAX;
2842         skinframe->avgcolor[3] = 1;
2843
2844         return skinframe;
2845 }
2846
2847 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2848 {
2849         int x, y;
2850         static unsigned char pix[16][16][4];
2851
2852         if (cls.state == ca_dedicated)
2853                 return NULL;
2854
2855         // this makes a light grey/dark grey checkerboard texture
2856         if (!pix[0][0][3])
2857         {
2858                 for (y = 0; y < 16; y++)
2859                 {
2860                         for (x = 0; x < 16; x++)
2861                         {
2862                                 if ((y < 8) ^ (x < 8))
2863                                 {
2864                                         pix[y][x][0] = 128;
2865                                         pix[y][x][1] = 128;
2866                                         pix[y][x][2] = 128;
2867                                         pix[y][x][3] = 255;
2868                                 }
2869                                 else
2870                                 {
2871                                         pix[y][x][0] = 64;
2872                                         pix[y][x][1] = 64;
2873                                         pix[y][x][2] = 64;
2874                                         pix[y][x][3] = 255;
2875                                 }
2876                         }
2877                 }
2878         }
2879
2880         return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, pix[0][0], 16, 16, 0, 0, 0, false);
2881 }
2882
2883 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qboolean sRGB)
2884 {
2885         skinframe_t *skinframe;
2886         if (cls.state == ca_dedicated)
2887                 return NULL;
2888         // if already loaded just return it, otherwise make a new skinframe
2889         skinframe = R_SkinFrame_Find(name, textureflags, width, height, 0, true);
2890         if (skinframe->base)
2891                 return skinframe;
2892         textureflags &= ~TEXF_FORCE_RELOAD;
2893         skinframe->stain = NULL;
2894         skinframe->merged = NULL;
2895         skinframe->base = NULL;
2896         skinframe->pants = NULL;
2897         skinframe->shirt = NULL;
2898         skinframe->nmap = NULL;
2899         skinframe->gloss = NULL;
2900         skinframe->glow = NULL;
2901         skinframe->fog = NULL;
2902         skinframe->reflect = NULL;
2903         skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2904         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2905         if (!tex)
2906                 return NULL;
2907         if (developer_loading.integer)
2908                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2909         skinframe->base = skinframe->merged = tex;
2910         Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2911         return skinframe;
2912 }
2913
2914 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2915 typedef struct suffixinfo_s
2916 {
2917         const char *suffix;
2918         qboolean flipx, flipy, flipdiagonal;
2919 }
2920 suffixinfo_t;
2921 static suffixinfo_t suffix[3][6] =
2922 {
2923         {
2924                 {"px",   false, false, false},
2925                 {"nx",   false, false, false},
2926                 {"py",   false, false, false},
2927                 {"ny",   false, false, false},
2928                 {"pz",   false, false, false},
2929                 {"nz",   false, false, false}
2930         },
2931         {
2932                 {"posx", false, false, false},
2933                 {"negx", false, false, false},
2934                 {"posy", false, false, false},
2935                 {"negy", false, false, false},
2936                 {"posz", false, false, false},
2937                 {"negz", false, false, false}
2938         },
2939         {
2940                 {"rt",    true, false,  true},
2941                 {"lf",   false,  true,  true},
2942                 {"ft",    true,  true, false},
2943                 {"bk",   false, false, false},
2944                 {"up",    true, false,  true},
2945                 {"dn",    true, false,  true}
2946         }
2947 };
2948
2949 static int componentorder[4] = {0, 1, 2, 3};
2950
2951 static rtexture_t *R_LoadCubemap(const char *basename)
2952 {
2953         int i, j, cubemapsize;
2954         unsigned char *cubemappixels, *image_buffer;
2955         rtexture_t *cubemaptexture;
2956         char name[256];
2957         // must start 0 so the first loadimagepixels has no requested width/height
2958         cubemapsize = 0;
2959         cubemappixels = NULL;
2960         cubemaptexture = NULL;
2961         // keep trying different suffix groups (posx, px, rt) until one loads
2962         for (j = 0;j < 3 && !cubemappixels;j++)
2963         {
2964                 // load the 6 images in the suffix group
2965                 for (i = 0;i < 6;i++)
2966                 {
2967                         // generate an image name based on the base and and suffix
2968                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2969                         // load it
2970                         if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
2971                         {
2972                                 // an image loaded, make sure width and height are equal
2973                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
2974                                 {
2975                                         // if this is the first image to load successfully, allocate the cubemap memory
2976                                         if (!cubemappixels && image_width >= 1)
2977                                         {
2978                                                 cubemapsize = image_width;
2979                                                 // note this clears to black, so unavailable sides are black
2980                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2981                                         }
2982                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2983                                         if (cubemappixels)
2984                                                 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);
2985                                 }
2986                                 else
2987                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2988                                 // free the image
2989                                 Mem_Free(image_buffer);
2990                         }
2991                 }
2992         }
2993         // if a cubemap loaded, upload it
2994         if (cubemappixels)
2995         {
2996                 if (developer_loading.integer)
2997                         Con_Printf("loading cubemap \"%s\"\n", basename);
2998
2999                 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);
3000                 Mem_Free(cubemappixels);
3001         }
3002         else
3003         {
3004                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
3005                 if (developer_loading.integer)
3006                 {
3007                         Con_Printf("(tried tried images ");
3008                         for (j = 0;j < 3;j++)
3009                                 for (i = 0;i < 6;i++)
3010                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3011                         Con_Print(" and was unable to find any of them).\n");
3012                 }
3013         }
3014         return cubemaptexture;
3015 }
3016
3017 rtexture_t *R_GetCubemap(const char *basename)
3018 {
3019         int i;
3020         for (i = 0;i < r_texture_numcubemaps;i++)
3021                 if (r_texture_cubemaps[i] != NULL)
3022                         if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
3023                                 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
3024         if (i >= MAX_CUBEMAPS || !r_main_mempool)
3025                 return r_texture_whitecube;
3026         r_texture_numcubemaps++;
3027         r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
3028         strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
3029         r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
3030         return r_texture_cubemaps[i]->texture;
3031 }
3032
3033 static void R_Main_FreeViewCache(void)
3034 {
3035         if (r_refdef.viewcache.entityvisible)
3036                 Mem_Free(r_refdef.viewcache.entityvisible);
3037         if (r_refdef.viewcache.world_pvsbits)
3038                 Mem_Free(r_refdef.viewcache.world_pvsbits);
3039         if (r_refdef.viewcache.world_leafvisible)
3040                 Mem_Free(r_refdef.viewcache.world_leafvisible);
3041         if (r_refdef.viewcache.world_surfacevisible)
3042                 Mem_Free(r_refdef.viewcache.world_surfacevisible);
3043         memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
3044 }
3045
3046 static void R_Main_ResizeViewCache(void)
3047 {
3048         int numentities = r_refdef.scene.numentities;
3049         int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
3050         int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
3051         int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
3052         int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
3053         if (r_refdef.viewcache.maxentities < numentities)
3054         {
3055                 r_refdef.viewcache.maxentities = numentities;
3056                 if (r_refdef.viewcache.entityvisible)
3057                         Mem_Free(r_refdef.viewcache.entityvisible);
3058                 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
3059         }
3060         if (r_refdef.viewcache.world_numclusters != numclusters)
3061         {
3062                 r_refdef.viewcache.world_numclusters = numclusters;
3063                 r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
3064                 if (r_refdef.viewcache.world_pvsbits)
3065                         Mem_Free(r_refdef.viewcache.world_pvsbits);
3066                 r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
3067         }
3068         if (r_refdef.viewcache.world_numleafs != numleafs)
3069         {
3070                 r_refdef.viewcache.world_numleafs = numleafs;
3071                 if (r_refdef.viewcache.world_leafvisible)
3072                         Mem_Free(r_refdef.viewcache.world_leafvisible);
3073                 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
3074         }
3075         if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
3076         {
3077                 r_refdef.viewcache.world_numsurfaces = numsurfaces;
3078                 if (r_refdef.viewcache.world_surfacevisible)
3079                         Mem_Free(r_refdef.viewcache.world_surfacevisible);
3080                 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
3081         }
3082 }
3083
3084 extern rtexture_t *loadingscreentexture;
3085 static void gl_main_start(void)
3086 {
3087         loadingscreentexture = NULL;
3088         r_texture_blanknormalmap = NULL;
3089         r_texture_white = NULL;
3090         r_texture_grey128 = NULL;
3091         r_texture_black = NULL;
3092         r_texture_whitecube = NULL;
3093         r_texture_normalizationcube = NULL;
3094         r_texture_fogattenuation = NULL;
3095         r_texture_fogheighttexture = NULL;
3096         r_texture_gammaramps = NULL;
3097         r_texture_numcubemaps = 0;
3098         r_uniformbufferalignment = 32;
3099
3100         r_loaddds = r_texture_dds_load.integer != 0;
3101         r_savedds = vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3102
3103         switch(vid.renderpath)
3104         {
3105         case RENDERPATH_GL32:
3106         case RENDERPATH_GLES2:
3107                 Cvar_SetValueQuick(&r_textureunits, MAX_TEXTUREUNITS);
3108                 Cvar_SetValueQuick(&gl_combine, 1);
3109                 Cvar_SetValueQuick(&r_glsl, 1);
3110                 r_loadnormalmap = true;
3111                 r_loadgloss = true;
3112                 r_loadfog = false;
3113 #ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
3114                 qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
3115 #endif
3116                 break;
3117         }
3118
3119         R_AnimCache_Free();
3120         R_FrameData_Reset();
3121         R_BufferData_Reset();
3122
3123         r_numqueries = 0;
3124         r_maxqueries = 0;
3125         memset(r_queries, 0, sizeof(r_queries));
3126
3127         r_qwskincache = NULL;
3128         r_qwskincache_size = 0;
3129
3130         // due to caching of texture_t references, the collision cache must be reset
3131         Collision_Cache_Reset(true);
3132
3133         // set up r_skinframe loading system for textures
3134         memset(&r_skinframe, 0, sizeof(r_skinframe));
3135         r_skinframe.loadsequence = 1;
3136         Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
3137
3138         r_main_texturepool = R_AllocTexturePool();
3139         R_BuildBlankTextures();
3140         R_BuildNoTexture();
3141         R_BuildWhiteCube();
3142         R_BuildNormalizationCube();
3143         r_texture_fogattenuation = NULL;
3144         r_texture_fogheighttexture = NULL;
3145         r_texture_gammaramps = NULL;
3146         //r_texture_fogintensity = NULL;
3147         memset(&r_fb, 0, sizeof(r_fb));
3148         Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
3149         r_glsl_permutation = NULL;
3150         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3151         Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
3152         memset(&r_svbsp, 0, sizeof (r_svbsp));
3153
3154         memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
3155         r_texture_numcubemaps = 0;
3156
3157         r_refdef.fogmasktable_density = 0;
3158
3159 #ifdef __ANDROID__
3160         // For Steelstorm Android
3161         // FIXME CACHE the program and reload
3162         // FIXME see possible combinations for SS:BR android
3163         Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
3164         R_SetupShader_SetPermutationGLSL(0, 12);
3165         R_SetupShader_SetPermutationGLSL(0, 13);
3166         R_SetupShader_SetPermutationGLSL(0, 8388621);
3167         R_SetupShader_SetPermutationGLSL(3, 0);
3168         R_SetupShader_SetPermutationGLSL(3, 2048);
3169         R_SetupShader_SetPermutationGLSL(5, 0);
3170         R_SetupShader_SetPermutationGLSL(5, 2);
3171         R_SetupShader_SetPermutationGLSL(5, 2048);
3172         R_SetupShader_SetPermutationGLSL(5, 8388608);
3173         R_SetupShader_SetPermutationGLSL(11, 1);
3174         R_SetupShader_SetPermutationGLSL(11, 2049);
3175         R_SetupShader_SetPermutationGLSL(11, 8193);
3176         R_SetupShader_SetPermutationGLSL(11, 10241);
3177         Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
3178 #endif
3179 }
3180
3181 extern unsigned int r_shadow_occlusion_buf;
3182
3183 static void gl_main_shutdown(void)
3184 {
3185         R_RenderTarget_FreeUnused(true);
3186         Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
3187         R_AnimCache_Free();
3188         R_FrameData_Reset();
3189         R_BufferData_Reset();
3190
3191         R_Main_FreeViewCache();
3192
3193         switch(vid.renderpath)
3194         {
3195         case RENDERPATH_GL32:
3196         case RENDERPATH_GLES2:
3197 #if defined(GL_SAMPLES_PASSED) && !defined(USE_GLES2)
3198                 if (r_maxqueries)
3199                         qglDeleteQueries(r_maxqueries, r_queries);
3200 #endif
3201                 break;
3202         }
3203         r_shadow_occlusion_buf = 0;
3204         r_numqueries = 0;
3205         r_maxqueries = 0;
3206         memset(r_queries, 0, sizeof(r_queries));
3207
3208         r_qwskincache = NULL;
3209         r_qwskincache_size = 0;
3210
3211         // clear out the r_skinframe state
3212         Mem_ExpandableArray_FreeArray(&r_skinframe.array);
3213         memset(&r_skinframe, 0, sizeof(r_skinframe));
3214
3215         if (r_svbsp.nodes)
3216                 Mem_Free(r_svbsp.nodes);
3217         memset(&r_svbsp, 0, sizeof (r_svbsp));
3218         R_FreeTexturePool(&r_main_texturepool);
3219         loadingscreentexture = NULL;
3220         r_texture_blanknormalmap = NULL;
3221         r_texture_white = NULL;
3222         r_texture_grey128 = NULL;
3223         r_texture_black = NULL;
3224         r_texture_whitecube = NULL;
3225         r_texture_normalizationcube = NULL;
3226         r_texture_fogattenuation = NULL;
3227         r_texture_fogheighttexture = NULL;
3228         r_texture_gammaramps = NULL;
3229         r_texture_numcubemaps = 0;
3230         //r_texture_fogintensity = NULL;
3231         memset(&r_fb, 0, sizeof(r_fb));
3232         R_GLSL_Restart_f(&cmd_client);
3233
3234         r_glsl_permutation = NULL;
3235         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3236         Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
3237 }
3238
3239 static void gl_main_newmap(void)
3240 {
3241         // FIXME: move this code to client
3242         char *entities, entname[MAX_QPATH];
3243         if (r_qwskincache)
3244                 Mem_Free(r_qwskincache);
3245         r_qwskincache = NULL;
3246         r_qwskincache_size = 0;
3247         if (cl.worldmodel)
3248         {
3249                 dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension);
3250                 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
3251                 {
3252                         CL_ParseEntityLump(entities);
3253                         Mem_Free(entities);
3254                         return;
3255                 }
3256                 if (cl.worldmodel->brush.entities)
3257                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
3258         }
3259         R_Main_FreeViewCache();
3260
3261         R_FrameData_Reset();
3262         R_BufferData_Reset();
3263 }
3264
3265 void GL_Main_Init(void)
3266 {
3267         int i;
3268         r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
3269         R_InitShaderModeInfo();
3270
3271         Cmd_AddCommand(&cmd_client, "r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
3272         Cmd_AddCommand(&cmd_client, "r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
3273         // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
3274         if (gamemode == GAME_NEHAHRA)
3275         {
3276                 Cvar_RegisterVariable (&gl_fogenable);
3277                 Cvar_RegisterVariable (&gl_fogdensity);
3278                 Cvar_RegisterVariable (&gl_fogred);
3279                 Cvar_RegisterVariable (&gl_foggreen);
3280                 Cvar_RegisterVariable (&gl_fogblue);
3281                 Cvar_RegisterVariable (&gl_fogstart);
3282                 Cvar_RegisterVariable (&gl_fogend);
3283                 Cvar_RegisterVariable (&gl_skyclip);
3284         }
3285         Cvar_RegisterVariable(&r_motionblur);
3286         Cvar_RegisterVariable(&r_damageblur);
3287         Cvar_RegisterVariable(&r_motionblur_averaging);
3288         Cvar_RegisterVariable(&r_motionblur_randomize);
3289         Cvar_RegisterVariable(&r_motionblur_minblur);
3290         Cvar_RegisterVariable(&r_motionblur_maxblur);
3291         Cvar_RegisterVariable(&r_motionblur_velocityfactor);
3292         Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed);
3293         Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed);
3294         Cvar_RegisterVariable(&r_motionblur_mousefactor);
3295         Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed);
3296         Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed);
3297         Cvar_RegisterVariable(&r_depthfirst);
3298         Cvar_RegisterVariable(&r_useinfinitefarclip);
3299         Cvar_RegisterVariable(&r_farclip_base);
3300         Cvar_RegisterVariable(&r_farclip_world);
3301         Cvar_RegisterVariable(&r_nearclip);
3302         Cvar_RegisterVariable(&r_deformvertexes);
3303         Cvar_RegisterVariable(&r_transparent);
3304         Cvar_RegisterVariable(&r_transparent_alphatocoverage);
3305         Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
3306         Cvar_RegisterVariable(&r_transparent_useplanardistance);
3307         Cvar_RegisterVariable(&r_showoverdraw);
3308         Cvar_RegisterVariable(&r_showbboxes);
3309         Cvar_RegisterVariable(&r_showbboxes_client);
3310         Cvar_RegisterVariable(&r_showsurfaces);
3311         Cvar_RegisterVariable(&r_showtris);
3312         Cvar_RegisterVariable(&r_shownormals);
3313         Cvar_RegisterVariable(&r_showlighting);
3314         Cvar_RegisterVariable(&r_showcollisionbrushes);
3315         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
3316         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
3317         Cvar_RegisterVariable(&r_showdisabledepthtest);
3318         Cvar_RegisterVariable(&r_showspriteedges);
3319         Cvar_RegisterVariable(&r_showparticleedges);
3320         Cvar_RegisterVariable(&r_drawportals);
3321         Cvar_RegisterVariable(&r_drawentities);
3322         Cvar_RegisterVariable(&r_draw2d);
3323         Cvar_RegisterVariable(&r_drawworld);
3324         Cvar_RegisterVariable(&r_cullentities_trace);
3325         Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
3326         Cvar_RegisterVariable(&r_cullentities_trace_samples);
3327         Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
3328         Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
3329         Cvar_RegisterVariable(&r_cullentities_trace_expand);
3330         Cvar_RegisterVariable(&r_cullentities_trace_pad);
3331         Cvar_RegisterVariable(&r_cullentities_trace_delay);
3332         Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
3333         Cvar_RegisterVariable(&r_sortentities);
3334         Cvar_RegisterVariable(&r_drawviewmodel);
3335         Cvar_RegisterVariable(&r_drawexteriormodel);
3336         Cvar_RegisterVariable(&r_speeds);
3337         Cvar_RegisterVariable(&r_fullbrights);
3338         Cvar_RegisterVariable(&r_wateralpha);
3339         Cvar_RegisterVariable(&r_dynamic);
3340         Cvar_RegisterVariable(&r_fullbright_directed);
3341         Cvar_RegisterVariable(&r_fullbright_directed_ambient);
3342         Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
3343         Cvar_RegisterVariable(&r_fullbright_directed_pitch);
3344         Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
3345         Cvar_RegisterVariable(&r_fullbright);
3346         Cvar_RegisterVariable(&r_shadows);
3347         Cvar_RegisterVariable(&r_shadows_darken);
3348         Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
3349         Cvar_RegisterVariable(&r_shadows_castfrombmodels);
3350         Cvar_RegisterVariable(&r_shadows_throwdistance);
3351         Cvar_RegisterVariable(&r_shadows_throwdirection);
3352         Cvar_RegisterVariable(&r_shadows_focus);
3353         Cvar_RegisterVariable(&r_shadows_shadowmapscale);
3354         Cvar_RegisterVariable(&r_shadows_shadowmapbias);
3355         Cvar_RegisterVariable(&r_q1bsp_skymasking);
3356         Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
3357         Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
3358         Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
3359         Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
3360         Cvar_RegisterVariable(&r_fog_exp2);
3361         Cvar_RegisterVariable(&r_fog_clear);
3362         Cvar_RegisterVariable(&r_drawfog);
3363         Cvar_RegisterVariable(&r_transparentdepthmasking);
3364         Cvar_RegisterVariable(&r_transparent_sortmindist);
3365         Cvar_RegisterVariable(&r_transparent_sortmaxdist);
3366         Cvar_RegisterVariable(&r_transparent_sortarraysize);
3367         Cvar_RegisterVariable(&r_texture_dds_load);
3368         Cvar_RegisterVariable(&r_texture_dds_save);
3369         Cvar_RegisterVariable(&r_textureunits);
3370         Cvar_RegisterVariable(&gl_combine);
3371         Cvar_RegisterVariable(&r_usedepthtextures);
3372         Cvar_RegisterVariable(&r_viewfbo);
3373         Cvar_RegisterVariable(&r_rendertarget_debug);
3374         Cvar_RegisterVariable(&r_viewscale);
3375         Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3376         Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3377         Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3378         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3379         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3380         Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3381         Cvar_RegisterVariable(&r_glsl);
3382         Cvar_RegisterVariable(&r_glsl_deluxemapping);
3383         Cvar_RegisterVariable(&r_glsl_offsetmapping);
3384         Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3385         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3386         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3387         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3388         Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3389         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3390         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3391         Cvar_RegisterVariable(&r_glsl_postprocess);
3392         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3393         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3394         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3395         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3396         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3397         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3398         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3399         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3400         Cvar_RegisterVariable(&r_celshading);
3401         Cvar_RegisterVariable(&r_celoutlines);
3402
3403         Cvar_RegisterVariable(&r_water);
3404         Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3405         Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3406         Cvar_RegisterVariable(&r_water_clippingplanebias);
3407         Cvar_RegisterVariable(&r_water_refractdistort);
3408         Cvar_RegisterVariable(&r_water_reflectdistort);
3409         Cvar_RegisterVariable(&r_water_scissormode);
3410         Cvar_RegisterVariable(&r_water_lowquality);
3411         Cvar_RegisterVariable(&r_water_hideplayer);
3412
3413         Cvar_RegisterVariable(&r_lerpsprites);
3414         Cvar_RegisterVariable(&r_lerpmodels);
3415         Cvar_RegisterVariable(&r_lerplightstyles);
3416         Cvar_RegisterVariable(&r_waterscroll);
3417         Cvar_RegisterVariable(&r_bloom);
3418         Cvar_RegisterVariable(&r_colorfringe);
3419         Cvar_RegisterVariable(&r_bloom_colorscale);
3420         Cvar_RegisterVariable(&r_bloom_brighten);
3421         Cvar_RegisterVariable(&r_bloom_blur);
3422         Cvar_RegisterVariable(&r_bloom_resolution);
3423         Cvar_RegisterVariable(&r_bloom_colorexponent);
3424         Cvar_RegisterVariable(&r_bloom_colorsubtract);
3425         Cvar_RegisterVariable(&r_bloom_scenebrightness);
3426         Cvar_RegisterVariable(&r_hdr_scenebrightness);
3427         Cvar_RegisterVariable(&r_hdr_glowintensity);
3428         Cvar_RegisterVariable(&r_hdr_irisadaptation);
3429         Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3430         Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3431         Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3432         Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3433         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3434         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3435         Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3436         Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3437         Cvar_RegisterVariable(&developer_texturelogging);
3438         Cvar_RegisterVariable(&gl_lightmaps);
3439         Cvar_RegisterVariable(&r_test);
3440         Cvar_RegisterVariable(&r_batch_multidraw);
3441         Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3442         Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3443         Cvar_RegisterVariable(&r_glsl_skeletal);
3444         Cvar_RegisterVariable(&r_glsl_saturation);
3445         Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3446         Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3447         Cvar_RegisterVariable(&r_framedatasize);
3448         for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3449                 Cvar_RegisterVariable(&r_buffermegs[i]);
3450         Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3451         if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3452                 Cvar_SetValue(&cvars_all, "r_fullbrights", 0);
3453 #ifdef DP_MOBILETOUCH
3454         // GLES devices have terrible depth precision in general, so...
3455         Cvar_SetValueQuick(&r_nearclip, 4);
3456         Cvar_SetValueQuick(&r_farclip_base, 4096);
3457         Cvar_SetValueQuick(&r_farclip_world, 0);
3458         Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3459 #endif
3460         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3461 }
3462
3463 void Render_Init(void)
3464 {
3465         gl_backend_init();
3466         R_Textures_Init();
3467         GL_Main_Init();
3468         Font_Init();
3469         GL_Draw_Init();
3470         R_Shadow_Init();
3471         R_Sky_Init();
3472         GL_Surf_Init();
3473         Sbar_Init();
3474         R_Particles_Init();
3475         R_Explosion_Init();
3476         R_LightningBeams_Init();
3477         Mod_RenderInit();
3478 }
3479
3480 int R_CullBox(const vec3_t mins, const vec3_t maxs)
3481 {
3482         int i;
3483         mplane_t *p;
3484         if (r_trippy.integer)
3485                 return false;
3486         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
3487         {
3488                 p = r_refdef.view.frustum + i;
3489                 switch(p->signbits)
3490                 {
3491                 default:
3492                 case 0:
3493                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3494                                 return true;
3495                         break;
3496                 case 1:
3497                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3498                                 return true;
3499                         break;
3500                 case 2:
3501                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3502                                 return true;
3503                         break;
3504                 case 3:
3505                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3506                                 return true;
3507                         break;
3508                 case 4:
3509                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3510                                 return true;
3511                         break;
3512                 case 5:
3513                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3514                                 return true;
3515                         break;
3516                 case 6:
3517                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3518                                 return true;
3519                         break;
3520                 case 7:
3521                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3522                                 return true;
3523                         break;
3524                 }
3525         }
3526         return false;
3527 }
3528
3529 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3530 {
3531         int i;
3532         const mplane_t *p;
3533         if (r_trippy.integer)
3534                 return false;
3535         for (i = 0;i < numplanes;i++)
3536         {
3537                 p = planes + i;
3538                 switch(p->signbits)
3539                 {
3540                 default:
3541                 case 0:
3542                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3543                                 return true;
3544                         break;
3545                 case 1:
3546                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3547                                 return true;
3548                         break;
3549                 case 2:
3550                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3551                                 return true;
3552                         break;
3553                 case 3:
3554                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3555                                 return true;
3556                         break;
3557                 case 4:
3558                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3559                                 return true;
3560                         break;
3561                 case 5:
3562                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3563                                 return true;
3564                         break;
3565                 case 6:
3566                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3567                                 return true;
3568                         break;
3569                 case 7:
3570                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3571                                 return true;
3572                         break;
3573                 }
3574         }
3575         return false;
3576 }
3577
3578 //==================================================================================
3579
3580 // LadyHavoc: this stores temporary data used within the same frame
3581
3582 typedef struct r_framedata_mem_s
3583 {
3584         struct r_framedata_mem_s *purge; // older mem block to free on next frame
3585         size_t size; // how much usable space
3586         size_t current; // how much space in use
3587         size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3588         size_t wantedsize; // how much space was allocated
3589         unsigned char *data; // start of real data (16byte aligned)
3590 }
3591 r_framedata_mem_t;
3592
3593 static r_framedata_mem_t *r_framedata_mem;
3594
3595 void R_FrameData_Reset(void)
3596 {
3597         while (r_framedata_mem)
3598         {
3599                 r_framedata_mem_t *next = r_framedata_mem->purge;
3600                 Mem_Free(r_framedata_mem);
3601                 r_framedata_mem = next;
3602         }
3603 }
3604
3605 static void R_FrameData_Resize(qboolean mustgrow)
3606 {
3607         size_t wantedsize;
3608         wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3609         wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3610         if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3611         {
3612                 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3613                 newmem->wantedsize = wantedsize;
3614                 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3615                 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3616                 newmem->current = 0;
3617                 newmem->mark = 0;
3618                 newmem->purge = r_framedata_mem;
3619                 r_framedata_mem = newmem;
3620         }
3621 }
3622
3623 void R_FrameData_NewFrame(void)
3624 {
3625         R_FrameData_Resize(false);
3626         if (!r_framedata_mem)
3627                 return;
3628         // if we ran out of space on the last frame, free the old memory now
3629         while (r_framedata_mem->purge)
3630         {
3631                 // repeatedly remove the second item in the list, leaving only head
3632                 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3633                 Mem_Free(r_framedata_mem->purge);
3634                 r_framedata_mem->purge = next;
3635         }
3636         // reset the current mem pointer
3637         r_framedata_mem->current = 0;
3638         r_framedata_mem->mark = 0;
3639 }
3640
3641 void *R_FrameData_Alloc(size_t size)
3642 {
3643         void *data;
3644         float newvalue;
3645
3646         // align to 16 byte boundary - the data pointer is already aligned, so we
3647         // only need to ensure the size of every allocation is also aligned
3648         size = (size + 15) & ~15;
3649
3650         while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3651         {
3652                 // emergency - we ran out of space, allocate more memory
3653                 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3654                 newvalue = r_framedatasize.value * 2.0f;
3655                 // 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
3656                 if (sizeof(size_t) >= 8)
3657                         newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3658                 else
3659                         newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3660                 // this might not be a growing it, but we'll allocate another buffer every time
3661                 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3662                 R_FrameData_Resize(true);
3663         }
3664
3665         data = r_framedata_mem->data + r_framedata_mem->current;
3666         r_framedata_mem->current += size;
3667
3668         // count the usage for stats
3669         r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3670         r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3671
3672         return (void *)data;
3673 }
3674
3675 void *R_FrameData_Store(size_t size, void *data)
3676 {
3677         void *d = R_FrameData_Alloc(size);
3678         if (d && data)
3679                 memcpy(d, data, size);
3680         return d;
3681 }
3682
3683 void R_FrameData_SetMark(void)
3684 {
3685         if (!r_framedata_mem)
3686                 return;
3687         r_framedata_mem->mark = r_framedata_mem->current;
3688 }
3689
3690 void R_FrameData_ReturnToMark(void)
3691 {
3692         if (!r_framedata_mem)
3693                 return;
3694         r_framedata_mem->current = r_framedata_mem->mark;
3695 }
3696
3697 //==================================================================================
3698
3699 // avoid reusing the same buffer objects on consecutive frames
3700 #define R_BUFFERDATA_CYCLE 3
3701
3702 typedef struct r_bufferdata_buffer_s
3703 {
3704         struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3705         size_t size; // how much usable space
3706         size_t current; // how much space in use
3707         r_meshbuffer_t *buffer; // the buffer itself
3708 }
3709 r_bufferdata_buffer_t;
3710
3711 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3712 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3713
3714 /// frees all dynamic buffers
3715 void R_BufferData_Reset(void)
3716 {
3717         int cycle, type;
3718         r_bufferdata_buffer_t **p, *mem;
3719         for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3720         {
3721                 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3722                 {
3723                         // free all buffers
3724                         p = &r_bufferdata_buffer[cycle][type];
3725                         while (*p)
3726                         {
3727                                 mem = *p;
3728                                 *p = (*p)->purge;
3729                                 if (mem->buffer)
3730                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3731                                 Mem_Free(mem);
3732                         }
3733                 }
3734         }
3735 }
3736
3737 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3738 static void R_BufferData_Resize(r_bufferdata_type_t type, qboolean mustgrow, size_t minsize)
3739 {
3740         r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3741         size_t size;
3742         float newvalue = r_buffermegs[type].value;
3743
3744         // increase the cvar if we have to (but only if we already have a mem)
3745         if (mustgrow && mem)
3746                 newvalue *= 2.0f;
3747         newvalue = bound(0.25f, newvalue, 256.0f);
3748         while (newvalue * 1024*1024 < minsize)
3749                 newvalue *= 2.0f;
3750
3751         // clamp the cvar to valid range
3752         newvalue = bound(0.25f, newvalue, 256.0f);
3753         if (r_buffermegs[type].value != newvalue)
3754                 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3755
3756         // calculate size in bytes
3757         size = (size_t)(newvalue * 1024*1024);
3758         size = bound(131072, size, 256*1024*1024);
3759
3760         // allocate a new buffer if the size is different (purge old one later)
3761         // or if we were told we must grow the buffer
3762         if (!mem || mem->size != size || mustgrow)
3763         {
3764                 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3765                 mem->size = size;
3766                 mem->current = 0;
3767                 if (type == R_BUFFERDATA_VERTEX)
3768                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3769                 else if (type == R_BUFFERDATA_INDEX16)
3770                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3771                 else if (type == R_BUFFERDATA_INDEX32)
3772                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3773                 else if (type == R_BUFFERDATA_UNIFORM)
3774                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3775                 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3776                 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3777         }
3778 }
3779
3780 void R_BufferData_NewFrame(void)
3781 {
3782         int type;
3783         r_bufferdata_buffer_t **p, *mem;
3784         // cycle to the next frame's buffers
3785         r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3786         // if we ran out of space on the last time we used these buffers, free the old memory now
3787         for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3788         {
3789                 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3790                 {
3791                         R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3792                         // free all but the head buffer, this is how we recycle obsolete
3793                         // buffers after they are no longer in use
3794                         p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3795                         while (*p)
3796                         {
3797                                 mem = *p;
3798                                 *p = (*p)->purge;
3799                                 if (mem->buffer)
3800                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3801                                 Mem_Free(mem);
3802                         }
3803                         // reset the current offset
3804                         r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3805                 }
3806         }
3807 }
3808
3809 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3810 {
3811         r_bufferdata_buffer_t *mem;
3812         int offset = 0;
3813         int padsize;
3814
3815         *returnbufferoffset = 0;
3816
3817         // align size to a byte boundary appropriate for the buffer type, this
3818         // makes all allocations have aligned start offsets
3819         if (type == R_BUFFERDATA_UNIFORM)
3820                 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3821         else
3822                 padsize = (datasize + 15) & ~15;
3823
3824         // if we ran out of space in this buffer we must allocate a new one
3825         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)
3826                 R_BufferData_Resize(type, true, padsize);
3827
3828         // if the resize did not give us enough memory, fail
3829         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)
3830                 Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3831
3832         mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3833         offset = (int)mem->current;
3834         mem->current += padsize;
3835
3836         // upload the data to the buffer at the chosen offset
3837         if (offset == 0)
3838                 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3839         R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3840
3841         // count the usage for stats
3842         r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3843         r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3844
3845         // return the buffer offset
3846         *returnbufferoffset = offset;
3847
3848         return mem->buffer;
3849 }
3850
3851 //==================================================================================
3852
3853 // LadyHavoc: animcache originally written by Echon, rewritten since then
3854
3855 /**
3856  * Animation cache prevents re-generating mesh data for an animated model
3857  * multiple times in one frame for lighting, shadowing, reflections, etc.
3858  */
3859
3860 void R_AnimCache_Free(void)
3861 {
3862 }
3863
3864 void R_AnimCache_ClearCache(void)
3865 {
3866         int i;
3867         entity_render_t *ent;
3868
3869         for (i = 0;i < r_refdef.scene.numentities;i++)
3870         {
3871                 ent = r_refdef.scene.entities[i];
3872                 ent->animcache_vertex3f = NULL;
3873                 ent->animcache_vertex3f_vertexbuffer = NULL;
3874                 ent->animcache_vertex3f_bufferoffset = 0;
3875                 ent->animcache_normal3f = NULL;
3876                 ent->animcache_normal3f_vertexbuffer = NULL;
3877                 ent->animcache_normal3f_bufferoffset = 0;
3878                 ent->animcache_svector3f = NULL;
3879                 ent->animcache_svector3f_vertexbuffer = NULL;
3880                 ent->animcache_svector3f_bufferoffset = 0;
3881                 ent->animcache_tvector3f = NULL;
3882                 ent->animcache_tvector3f_vertexbuffer = NULL;
3883                 ent->animcache_tvector3f_bufferoffset = 0;
3884                 ent->animcache_skeletaltransform3x4 = NULL;
3885                 ent->animcache_skeletaltransform3x4buffer = NULL;
3886                 ent->animcache_skeletaltransform3x4offset = 0;
3887                 ent->animcache_skeletaltransform3x4size = 0;
3888         }
3889 }
3890
3891 qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
3892 {
3893         dp_model_t *model = ent->model;
3894         int numvertices;
3895
3896         // see if this ent is worth caching
3897         if (!model || !model->Draw || !model->AnimateVertices)
3898                 return false;
3899         // nothing to cache if it contains no animations and has no skeleton
3900         if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3901                 return false;
3902         // see if it is already cached for gpuskeletal
3903         if (ent->animcache_skeletaltransform3x4)
3904                 return false;
3905         // see if it is already cached as a mesh
3906         if (ent->animcache_vertex3f)
3907         {
3908                 // check if we need to add normals or tangents
3909                 if (ent->animcache_normal3f)
3910                         wantnormals = false;
3911                 if (ent->animcache_svector3f)
3912                         wanttangents = false;
3913                 if (!wantnormals && !wanttangents)
3914                         return false;
3915         }
3916
3917         // check which kind of cache we need to generate
3918         if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3919         {
3920                 // cache the skeleton so the vertex shader can use it
3921                 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3922                 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3923                 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3924                 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3925                 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4); 
3926                 // note: this can fail if the buffer is at the grow limit
3927                 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3928                 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3929         }
3930         else if (ent->animcache_vertex3f)
3931         {
3932                 // mesh was already cached but we may need to add normals/tangents
3933                 // (this only happens with multiple views, reflections, cameras, etc)
3934                 if (wantnormals || wanttangents)
3935                 {
3936                         numvertices = model->surfmesh.num_vertices;
3937                         if (wantnormals)
3938                                 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3939                         if (wanttangents)
3940                         {
3941                                 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3942                                 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3943                         }
3944                         model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3945                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3946                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3947                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3948                 }
3949         }
3950         else
3951         {
3952                 // generate mesh cache
3953                 numvertices = model->surfmesh.num_vertices;
3954                 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3955                 if (wantnormals)
3956                         ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3957                 if (wanttangents)
3958                 {
3959                         ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3960                         ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3961                 }
3962                 model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
3963                 if (wantnormals || wanttangents)
3964                 {
3965                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3966                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3967                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3968                 }
3969                 r_refdef.stats[r_stat_animcache_shape_count] += 1;
3970                 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
3971                 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
3972         }
3973         return true;
3974 }
3975
3976 void R_AnimCache_CacheVisibleEntities(void)
3977 {
3978         int i;
3979
3980         // TODO: thread this
3981         // NOTE: R_PrepareRTLights() also caches entities
3982
3983         for (i = 0;i < r_refdef.scene.numentities;i++)
3984                 if (r_refdef.viewcache.entityvisible[i])
3985                         R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
3986 }
3987
3988 //==================================================================================
3989
3990 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)
3991 {
3992         int i;
3993         vec3_t eyemins, eyemaxs;
3994         vec3_t boxmins, boxmaxs;
3995         vec3_t padmins, padmaxs;
3996         vec3_t start;
3997         vec3_t end;
3998         dp_model_t *model = r_refdef.scene.worldmodel;
3999         static vec3_t positions[] = {
4000                 { 0.5f, 0.5f, 0.5f },
4001                 { 0.0f, 0.0f, 0.0f },
4002                 { 0.0f, 0.0f, 1.0f },
4003                 { 0.0f, 1.0f, 0.0f },
4004                 { 0.0f, 1.0f, 1.0f },
4005                 { 1.0f, 0.0f, 0.0f },
4006                 { 1.0f, 0.0f, 1.0f },
4007                 { 1.0f, 1.0f, 0.0f },
4008                 { 1.0f, 1.0f, 1.0f },
4009         };
4010
4011         // sample count can be set to -1 to skip this logic, for flicker-prone objects
4012         if (numsamples < 0)
4013                 return true;
4014
4015         // view origin is not used for culling in portal/reflection/refraction renders or isometric views
4016         if (!r_refdef.view.usevieworiginculling)
4017                 return true;
4018
4019         if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
4020                 return true;
4021
4022         // expand the eye box a little
4023         eyemins[0] = eye[0] - eyejitter;
4024         eyemaxs[0] = eye[0] + eyejitter;
4025         eyemins[1] = eye[1] - eyejitter;
4026         eyemaxs[1] = eye[1] + eyejitter;
4027         eyemins[2] = eye[2] - eyejitter;
4028         eyemaxs[2] = eye[2] + eyejitter;
4029         // expand the box a little
4030         boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
4031         boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
4032         boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
4033         boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
4034         boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
4035         boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
4036         // make an even larger box for the acceptable area
4037         padmins[0] = boxmins[0] - pad;
4038         padmaxs[0] = boxmaxs[0] + pad;
4039         padmins[1] = boxmins[1] - pad;
4040         padmaxs[1] = boxmaxs[1] + pad;
4041         padmins[2] = boxmins[2] - pad;
4042         padmaxs[2] = boxmaxs[2] + pad;
4043
4044         // return true if eye overlaps enlarged box
4045         if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
4046                 return true;
4047
4048         // try specific positions in the box first - note that these can be cached
4049         if (r_cullentities_trace_entityocclusion.integer)
4050         {
4051                 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
4052                 {
4053                         VectorCopy(eye, start);
4054                         end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
4055                         end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
4056                         end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
4057                         //trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
4058                         trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
4059                         // not picky - if the trace ended anywhere in the box we're good
4060                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4061                                 return true;
4062                 }
4063         }
4064         else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4065                 return true;
4066
4067         // try various random positions
4068         for (i = 0; i < numsamples; i++)
4069         {
4070                 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
4071                 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
4072                 if (r_cullentities_trace_entityocclusion.integer)
4073                 {
4074                         trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
4075                         // not picky - if the trace ended anywhere in the box we're good
4076                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4077                                 return true;
4078                 }
4079                 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4080                         return true;
4081         }
4082
4083         return false;
4084 }
4085
4086
4087 static void R_View_UpdateEntityVisible (void)
4088 {
4089         int i;
4090         int renderimask;
4091         int samples;
4092         entity_render_t *ent;
4093
4094         if (r_refdef.envmap || r_fb.water.hideplayer)
4095                 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
4096         else if (chase_active.integer || r_fb.water.renderingscene)
4097                 renderimask = RENDER_VIEWMODEL;
4098         else
4099                 renderimask = RENDER_EXTERIORMODEL;
4100         if (!r_drawviewmodel.integer)
4101                 renderimask |= RENDER_VIEWMODEL;
4102         if (!r_drawexteriormodel.integer)
4103                 renderimask |= RENDER_EXTERIORMODEL;
4104         memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4105         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4106         {
4107                 // worldmodel can check visibility
4108                 for (i = 0;i < r_refdef.scene.numentities;i++)
4109                 {
4110                         ent = r_refdef.scene.entities[i];
4111                         if (!(ent->flags & renderimask))
4112                         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)))
4113                         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))
4114                                 r_refdef.viewcache.entityvisible[i] = true;
4115                 }
4116         }
4117         else
4118         {
4119                 // no worldmodel or it can't check visibility
4120                 for (i = 0;i < r_refdef.scene.numentities;i++)
4121                 {
4122                         ent = r_refdef.scene.entities[i];
4123                         if (!(ent->flags & renderimask))
4124                         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)))
4125                                 r_refdef.viewcache.entityvisible[i] = true;
4126                 }
4127         }
4128         if (r_cullentities_trace.integer)
4129         {
4130                 for (i = 0;i < r_refdef.scene.numentities;i++)
4131                 {
4132                         if (!r_refdef.viewcache.entityvisible[i])
4133                                 continue;
4134                         ent = r_refdef.scene.entities[i];
4135                         if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4136                         {
4137                                 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4138                                 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))
4139                                         ent->last_trace_visibility = realtime;
4140                                 if (ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
4141                                         r_refdef.viewcache.entityvisible[i] = 0;
4142                         }
4143                 }
4144         }
4145 }
4146
4147 /// only used if skyrendermasked, and normally returns false
4148 static int R_DrawBrushModelsSky (void)
4149 {
4150         int i, sky;
4151         entity_render_t *ent;
4152
4153         sky = false;
4154         for (i = 0;i < r_refdef.scene.numentities;i++)
4155         {
4156                 if (!r_refdef.viewcache.entityvisible[i])
4157                         continue;
4158                 ent = r_refdef.scene.entities[i];
4159                 if (!ent->model || !ent->model->DrawSky)
4160                         continue;
4161                 ent->model->DrawSky(ent);
4162                 sky = true;
4163         }
4164         return sky;
4165 }
4166
4167 static void R_DrawNoModel(entity_render_t *ent);
4168 static void R_DrawModels(void)
4169 {
4170         int i;
4171         entity_render_t *ent;
4172
4173         for (i = 0;i < r_refdef.scene.numentities;i++)
4174         {
4175                 if (!r_refdef.viewcache.entityvisible[i])
4176                         continue;
4177                 ent = r_refdef.scene.entities[i];
4178                 r_refdef.stats[r_stat_entities]++;
4179                 /*
4180                 if (ent->model && !strncmp(ent->model->name, "models/proto_", 13))
4181                 {
4182                         vec3_t f, l, u, o;
4183                         Matrix4x4_ToVectors(&ent->matrix, f, l, u, o);
4184                         Con_Printf("R_DrawModels\n");
4185                         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]);
4186                         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);
4187                         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);
4188                 }
4189                 */
4190                 if (ent->model && ent->model->Draw != NULL)
4191                         ent->model->Draw(ent);
4192                 else
4193                         R_DrawNoModel(ent);
4194         }
4195 }
4196
4197 static void R_DrawModelsDepth(void)
4198 {
4199         int i;
4200         entity_render_t *ent;
4201
4202         for (i = 0;i < r_refdef.scene.numentities;i++)
4203         {
4204                 if (!r_refdef.viewcache.entityvisible[i])
4205                         continue;
4206                 ent = r_refdef.scene.entities[i];
4207                 if (ent->model && ent->model->DrawDepth != NULL)
4208                         ent->model->DrawDepth(ent);
4209         }
4210 }
4211
4212 static void R_DrawModelsDebug(void)
4213 {
4214         int i;
4215         entity_render_t *ent;
4216
4217         for (i = 0;i < r_refdef.scene.numentities;i++)
4218         {
4219                 if (!r_refdef.viewcache.entityvisible[i])
4220                         continue;
4221                 ent = r_refdef.scene.entities[i];
4222                 if (ent->model && ent->model->DrawDebug != NULL)
4223                         ent->model->DrawDebug(ent);
4224         }
4225 }
4226
4227 static void R_DrawModelsAddWaterPlanes(void)
4228 {
4229         int i;
4230         entity_render_t *ent;
4231
4232         for (i = 0;i < r_refdef.scene.numentities;i++)
4233         {
4234                 if (!r_refdef.viewcache.entityvisible[i])
4235                         continue;
4236                 ent = r_refdef.scene.entities[i];
4237                 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4238                         ent->model->DrawAddWaterPlanes(ent);
4239         }
4240 }
4241
4242 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}};
4243
4244 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4245 {
4246         if (r_hdr_irisadaptation.integer)
4247         {
4248                 vec3_t p;
4249                 vec3_t ambient;
4250                 vec3_t diffuse;
4251                 vec3_t diffusenormal;
4252                 vec3_t forward;
4253                 vec_t brightness = 0.0f;
4254                 vec_t goal;
4255                 vec_t current;
4256                 vec_t d;
4257                 int c;
4258                 VectorCopy(r_refdef.view.forward, forward);
4259                 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4260                 {
4261                         p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4262                         p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4263                         p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4264                         R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4265                         d = DotProduct(forward, diffusenormal);
4266                         brightness += VectorLength(ambient);
4267                         if (d > 0)
4268                                 brightness += d * VectorLength(diffuse);
4269                 }
4270                 brightness *= 1.0f / c;
4271                 brightness += 0.00001f; // make sure it's never zero
4272                 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4273                 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4274                 current = r_hdr_irisadaptation_value.value;
4275                 if (current < goal)
4276                         current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4277                 else if (current > goal)
4278                         current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4279                 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4280                         Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4281         }
4282         else if (r_hdr_irisadaptation_value.value != 1.0f)
4283                 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4284 }
4285
4286 static void R_View_SetFrustum(const int *scissor)
4287 {
4288         int i;
4289         double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4290         vec3_t forward, left, up, origin, v;
4291
4292         if(scissor)
4293         {
4294                 // flipped x coordinates (because x points left here)
4295                 fpx =  1.0 - 2.0 * (scissor[0]              - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4296                 fnx =  1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4297                 // non-flipped y coordinates
4298                 fny = -1.0 + 2.0 * (scissor[1]              - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4299                 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4300         }
4301
4302         // we can't trust r_refdef.view.forward and friends in reflected scenes
4303         Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4304
4305 #if 0
4306         r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4307         r_refdef.view.frustum[0].normal[1] = 0 - 0;
4308         r_refdef.view.frustum[0].normal[2] = -1 - 0;
4309         r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4310         r_refdef.view.frustum[1].normal[1] = 0 + 0;
4311         r_refdef.view.frustum[1].normal[2] = -1 + 0;
4312         r_refdef.view.frustum[2].normal[0] = 0 - 0;
4313         r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4314         r_refdef.view.frustum[2].normal[2] = -1 - 0;
4315         r_refdef.view.frustum[3].normal[0] = 0 + 0;
4316         r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4317         r_refdef.view.frustum[3].normal[2] = -1 + 0;
4318 #endif
4319
4320 #if 0
4321         zNear = r_refdef.nearclip;
4322         nudge = 1.0 - 1.0 / (1<<23);
4323         r_refdef.view.frustum[4].normal[0] = 0 - 0;
4324         r_refdef.view.frustum[4].normal[1] = 0 - 0;
4325         r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4326         r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4327         r_refdef.view.frustum[5].normal[0] = 0 + 0;
4328         r_refdef.view.frustum[5].normal[1] = 0 + 0;
4329         r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4330         r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4331 #endif
4332
4333
4334
4335 #if 0
4336         r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4337         r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4338         r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4339         r_refdef.view.frustum[0].dist = m[15] - m[12];
4340
4341         r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4342         r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4343         r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4344         r_refdef.view.frustum[1].dist = m[15] + m[12];
4345
4346         r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4347         r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4348         r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4349         r_refdef.view.frustum[2].dist = m[15] - m[13];
4350
4351         r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4352         r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4353         r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4354         r_refdef.view.frustum[3].dist = m[15] + m[13];
4355
4356         r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4357         r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4358         r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4359         r_refdef.view.frustum[4].dist = m[15] - m[14];
4360
4361         r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4362         r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4363         r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4364         r_refdef.view.frustum[5].dist = m[15] + m[14];
4365 #endif
4366
4367         if (r_refdef.view.useperspective)
4368         {
4369                 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4370                 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]);
4371                 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]);
4372                 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]);
4373                 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]);
4374
4375                 // then the normals from the corners relative to origin
4376                 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4377                 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4378                 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4379                 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4380
4381                 // in a NORMAL view, forward cross left == up
4382                 // in a REFLECTED view, forward cross left == down
4383                 // so our cross products above need to be adjusted for a left handed coordinate system
4384                 CrossProduct(forward, left, v);
4385                 if(DotProduct(v, up) < 0)
4386                 {
4387                         VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4388                         VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4389                         VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4390                         VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4391                 }
4392
4393                 // Leaving those out was a mistake, those were in the old code, and they
4394                 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4395                 // I couldn't reproduce it after adding those normalizations. --blub
4396                 VectorNormalize(r_refdef.view.frustum[0].normal);
4397                 VectorNormalize(r_refdef.view.frustum[1].normal);
4398                 VectorNormalize(r_refdef.view.frustum[2].normal);
4399                 VectorNormalize(r_refdef.view.frustum[3].normal);
4400
4401                 // make the corners absolute
4402                 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4403                 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4404                 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4405                 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4406
4407                 // one more normal
4408                 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4409
4410                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4411                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4412                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4413                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4414                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4415         }
4416         else
4417         {
4418                 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4419                 VectorScale(left,  1.0f, r_refdef.view.frustum[1].normal);
4420                 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4421                 VectorScale(up,  1.0f, r_refdef.view.frustum[3].normal);
4422                 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4423                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4424                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4425                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4426                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4427                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4428         }
4429         r_refdef.view.numfrustumplanes = 5;
4430
4431         if (r_refdef.view.useclipplane)
4432         {
4433                 r_refdef.view.numfrustumplanes = 6;
4434                 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4435         }
4436
4437         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4438                 PlaneClassify(r_refdef.view.frustum + i);
4439
4440         // LadyHavoc: note to all quake engine coders, Quake had a special case
4441         // for 90 degrees which assumed a square view (wrong), so I removed it,
4442         // Quake2 has it disabled as well.
4443
4444         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4445         //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4446         //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4447         //PlaneClassify(&frustum[0]);
4448
4449         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4450         //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4451         //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4452         //PlaneClassify(&frustum[1]);
4453
4454         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4455         //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4456         //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4457         //PlaneClassify(&frustum[2]);
4458
4459         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4460         //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4461         //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4462         //PlaneClassify(&frustum[3]);
4463
4464         // nearclip plane
4465         //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4466         //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4467         //PlaneClassify(&frustum[4]);
4468 }
4469
4470 static void R_View_UpdateWithScissor(const int *myscissor)
4471 {
4472         R_Main_ResizeViewCache();
4473         R_View_SetFrustum(myscissor);
4474         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4475         R_View_UpdateEntityVisible();
4476 }
4477
4478 static void R_View_Update(void)
4479 {
4480         R_Main_ResizeViewCache();
4481         R_View_SetFrustum(NULL);
4482         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4483         R_View_UpdateEntityVisible();
4484 }
4485
4486 float viewscalefpsadjusted = 1.0f;
4487
4488 void R_SetupView(qboolean allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4489 {
4490         const float *customclipplane = NULL;
4491         float plane[4];
4492         int /*rtwidth,*/ rtheight;
4493         if (r_refdef.view.useclipplane && allowwaterclippingplane)
4494         {
4495                 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4496                 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4497                 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4498                 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4499                         dist = r_refdef.view.clipplane.dist;
4500                 plane[0] = r_refdef.view.clipplane.normal[0];
4501                 plane[1] = r_refdef.view.clipplane.normal[1];
4502                 plane[2] = r_refdef.view.clipplane.normal[2];
4503                 plane[3] = -dist;
4504                 customclipplane = plane;
4505         }
4506
4507         //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
4508         rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
4509
4510         if (!r_refdef.view.useperspective)
4511                 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);
4512         else if (vid.stencil && r_useinfinitefarclip.integer)
4513                 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);
4514         else
4515                 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);
4516         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4517         R_SetViewport(&r_refdef.view.viewport);
4518 }
4519
4520 void R_EntityMatrix(const matrix4x4_t *matrix)
4521 {
4522         if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4523         {
4524                 gl_modelmatrixchanged = false;
4525                 gl_modelmatrix = *matrix;
4526                 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4527                 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4528                 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4529                 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4530                 CHECKGLERROR
4531                 switch(vid.renderpath)
4532                 {
4533                 case RENDERPATH_GL32:
4534                 case RENDERPATH_GLES2:
4535                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4536                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4537                         break;
4538                 }
4539         }
4540 }
4541
4542 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4543 {
4544         r_viewport_t viewport;
4545
4546         CHECKGLERROR
4547
4548         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
4549         R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4550         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4551         R_SetViewport(&viewport);
4552         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4553         GL_Color(1, 1, 1, 1);
4554         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4555         GL_BlendFunc(GL_ONE, GL_ZERO);
4556         GL_ScissorTest(false);
4557         GL_DepthMask(false);
4558         GL_DepthRange(0, 1);
4559         GL_DepthTest(false);
4560         GL_DepthFunc(GL_LEQUAL);
4561         R_EntityMatrix(&identitymatrix);
4562         R_Mesh_ResetTextureState();
4563         GL_PolygonOffset(0, 0);
4564         switch(vid.renderpath)
4565         {
4566         case RENDERPATH_GL32:
4567         case RENDERPATH_GLES2:
4568                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4569                 break;
4570         }
4571         GL_CullFace(GL_NONE);
4572
4573         CHECKGLERROR
4574 }
4575
4576 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4577 {
4578         R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4579 }
4580
4581 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4582 {
4583         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4584         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4585         GL_Color(1, 1, 1, 1);
4586         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4587         GL_BlendFunc(GL_ONE, GL_ZERO);
4588         GL_ScissorTest(true);
4589         GL_DepthMask(true);
4590         GL_DepthRange(0, 1);
4591         GL_DepthTest(true);
4592         GL_DepthFunc(GL_LEQUAL);
4593         R_EntityMatrix(&identitymatrix);
4594         R_Mesh_ResetTextureState();
4595         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4596         switch(vid.renderpath)
4597         {
4598         case RENDERPATH_GL32:
4599         case RENDERPATH_GLES2:
4600                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4601                 break;
4602         }
4603         GL_CullFace(r_refdef.view.cullface_back);
4604 }
4605
4606 /*
4607 ================
4608 R_RenderView_UpdateViewVectors
4609 ================
4610 */
4611 void R_RenderView_UpdateViewVectors(void)
4612 {
4613         // break apart the view matrix into vectors for various purposes
4614         // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4615         // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4616         Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4617         VectorNegate(r_refdef.view.left, r_refdef.view.right);
4618         // make an inverted copy of the view matrix for tracking sprites
4619         Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4620 }
4621
4622 void R_RenderTarget_FreeUnused(qboolean force)
4623 {
4624         unsigned int i, j, end;
4625         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4626         for (i = 0; i < end; i++)
4627         {
4628                 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4629                 // free resources for rendertargets that have not been used for a while
4630                 // (note: this check is run after the frame render, so any targets used
4631                 // this frame will not be affected even at low framerates)
4632                 if (r && (realtime - r->lastusetime > 0.2 || force))
4633                 {
4634                         if (r->fbo)
4635                                 R_Mesh_DestroyFramebufferObject(r->fbo);
4636                         for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4637                                 if (r->colortexture[j])
4638                                         R_FreeTexture(r->colortexture[j]);
4639                         if (r->depthtexture)
4640                                 R_FreeTexture(r->depthtexture);
4641                         Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4642                 }
4643         }
4644 }
4645
4646 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4647 {
4648         float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4649         x1 = x * iw;
4650         x2 = (x + w) * iw;
4651         y1 = (th - y) * ih;
4652         y2 = (th - y - h) * ih;
4653         texcoord2f[0] = x1;
4654         texcoord2f[2] = x2;
4655         texcoord2f[4] = x2;
4656         texcoord2f[6] = x1;
4657         texcoord2f[1] = y1;
4658         texcoord2f[3] = y1;
4659         texcoord2f[5] = y2;
4660         texcoord2f[7] = y2;
4661 }
4662
4663 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)
4664 {
4665         unsigned int i, j, end;
4666         r_rendertarget_t *r = NULL;
4667         char vabuf[256];
4668         // first try to reuse an existing slot if possible
4669         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4670         for (i = 0; i < end; i++)
4671         {
4672                 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4673                 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)
4674                         break;
4675         }
4676         if (i == end)
4677         {
4678                 // no unused exact match found, so we have to make one in the first unused slot
4679                 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4680                 r->texturewidth = texturewidth;
4681                 r->textureheight = textureheight;
4682                 r->colortextype[0] = colortextype0;
4683                 r->colortextype[1] = colortextype1;
4684                 r->colortextype[2] = colortextype2;
4685                 r->colortextype[3] = colortextype3;
4686                 r->depthtextype = depthtextype;
4687                 r->depthisrenderbuffer = depthisrenderbuffer;
4688                 for (j = 0; j < 4; j++)
4689                         if (r->colortextype[j])
4690                                 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);
4691                 if (r->depthtextype)
4692                 {
4693                         if (r->depthisrenderbuffer)
4694                                 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);
4695                         else
4696                                 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);
4697                 }
4698                 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4699         }
4700         r_refdef.stats[r_stat_rendertargets_used]++;
4701         r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4702         r->lastusetime = realtime;
4703         R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4704         return r;
4705 }
4706
4707 static void R_Water_StartFrame(int viewwidth, int viewheight)
4708 {
4709         int waterwidth, waterheight;
4710
4711         if (vid.width > (int)vid.maxtexturesize_2d || vid.height > (int)vid.maxtexturesize_2d)
4712                 return;
4713
4714         // set waterwidth and waterheight to the water resolution that will be
4715         // used (often less than the screen resolution for faster rendering)
4716         waterwidth = (int)bound(16, viewwidth * r_water_resolutionmultiplier.value, viewwidth);
4717         waterheight = (int)bound(16, viewheight * r_water_resolutionmultiplier.value, viewheight);
4718
4719         if (!r_water.integer || r_showsurfaces.integer)
4720                 waterwidth = waterheight = 0;
4721
4722         // set up variables that will be used in shader setup
4723         r_fb.water.waterwidth = waterwidth;
4724         r_fb.water.waterheight = waterheight;
4725         r_fb.water.texturewidth = waterwidth;
4726         r_fb.water.textureheight = waterheight;
4727         r_fb.water.camerawidth = waterwidth;
4728         r_fb.water.cameraheight = waterheight;
4729         r_fb.water.screenscale[0] = 0.5f;
4730         r_fb.water.screenscale[1] = 0.5f;
4731         r_fb.water.screencenter[0] = 0.5f;
4732         r_fb.water.screencenter[1] = 0.5f;
4733         r_fb.water.enabled = waterwidth != 0;
4734
4735         r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4736         r_fb.water.numwaterplanes = 0;
4737 }
4738
4739 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4740 {
4741         int planeindex, bestplaneindex, vertexindex;
4742         vec3_t mins, maxs, normal, center, v, n;
4743         vec_t planescore, bestplanescore;
4744         mplane_t plane;
4745         r_waterstate_waterplane_t *p;
4746         texture_t *t = R_GetCurrentTexture(surface->texture);
4747
4748         rsurface.texture = t;
4749         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4750         // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4751         if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4752                 return;
4753         // average the vertex normals, find the surface bounds (after deformvertexes)
4754         Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4755         Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4756         VectorCopy(n, normal);
4757         VectorCopy(v, mins);
4758         VectorCopy(v, maxs);
4759         for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4760         {
4761                 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4762                 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4763                 VectorAdd(normal, n, normal);
4764                 mins[0] = min(mins[0], v[0]);
4765                 mins[1] = min(mins[1], v[1]);
4766                 mins[2] = min(mins[2], v[2]);
4767                 maxs[0] = max(maxs[0], v[0]);
4768                 maxs[1] = max(maxs[1], v[1]);
4769                 maxs[2] = max(maxs[2], v[2]);
4770         }
4771         VectorNormalize(normal);
4772         VectorMAM(0.5f, mins, 0.5f, maxs, center);
4773
4774         VectorCopy(normal, plane.normal);
4775         VectorNormalize(plane.normal);
4776         plane.dist = DotProduct(center, plane.normal);
4777         PlaneClassify(&plane);
4778         if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4779         {
4780                 // skip backfaces (except if nocullface is set)
4781 //              if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4782 //                      return;
4783                 VectorNegate(plane.normal, plane.normal);
4784                 plane.dist *= -1;
4785                 PlaneClassify(&plane);
4786         }
4787
4788
4789         // find a matching plane if there is one
4790         bestplaneindex = -1;
4791         bestplanescore = 1048576.0f;
4792         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4793         {
4794                 if(p->camera_entity == t->camera_entity)
4795                 {
4796                         planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4797                         if (bestplaneindex < 0 || bestplanescore > planescore)
4798                         {
4799                                 bestplaneindex = planeindex;
4800                                 bestplanescore = planescore;
4801                         }
4802                 }
4803         }
4804         planeindex = bestplaneindex;
4805
4806         // if this surface does not fit any known plane rendered this frame, add one
4807         if (planeindex < 0 || bestplanescore > 0.001f)
4808         {
4809                 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4810                 {
4811                         // store the new plane
4812                         planeindex = r_fb.water.numwaterplanes++;
4813                         p = r_fb.water.waterplanes + planeindex;
4814                         p->plane = plane;
4815                         // clear materialflags and pvs
4816                         p->materialflags = 0;
4817                         p->pvsvalid = false;
4818                         p->camera_entity = t->camera_entity;
4819                         VectorCopy(mins, p->mins);
4820                         VectorCopy(maxs, p->maxs);
4821                 }
4822                 else
4823                 {
4824                         // We're totally screwed.
4825                         return;
4826                 }
4827         }
4828         else
4829         {
4830                 // merge mins/maxs when we're adding this surface to the plane
4831                 p = r_fb.water.waterplanes + planeindex;
4832                 p->mins[0] = min(p->mins[0], mins[0]);
4833                 p->mins[1] = min(p->mins[1], mins[1]);
4834                 p->mins[2] = min(p->mins[2], mins[2]);
4835                 p->maxs[0] = max(p->maxs[0], maxs[0]);
4836                 p->maxs[1] = max(p->maxs[1], maxs[1]);
4837                 p->maxs[2] = max(p->maxs[2], maxs[2]);
4838         }
4839         // merge this surface's materialflags into the waterplane
4840         p->materialflags |= t->currentmaterialflags;
4841         if(!(p->materialflags & MATERIALFLAG_CAMERA))
4842         {
4843                 // merge this surface's PVS into the waterplane
4844                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4845                  && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4846                 {
4847                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4848                         p->pvsvalid = true;
4849                 }
4850         }
4851 }
4852
4853 extern cvar_t r_drawparticles;
4854 extern cvar_t r_drawdecals;
4855
4856 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4857 {
4858         int myscissor[4];
4859         r_refdef_view_t originalview;
4860         r_refdef_view_t myview;
4861         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;
4862         r_waterstate_waterplane_t *p;
4863         vec3_t visorigin;
4864         r_rendertarget_t *rt;
4865
4866         originalview = r_refdef.view;
4867
4868         // lowquality hack, temporarily shut down some cvars and restore afterwards
4869         qualityreduction = r_water_lowquality.integer;
4870         if (qualityreduction > 0)
4871         {
4872                 if (qualityreduction >= 1)
4873                 {
4874                         old_r_shadows = r_shadows.integer;
4875                         old_r_worldrtlight = r_shadow_realtime_world.integer;
4876                         old_r_dlight = r_shadow_realtime_dlight.integer;
4877                         Cvar_SetValueQuick(&r_shadows, 0);
4878                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4879                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4880                 }
4881                 if (qualityreduction >= 2)
4882                 {
4883                         old_r_dynamic = r_dynamic.integer;
4884                         old_r_particles = r_drawparticles.integer;
4885                         old_r_decals = r_drawdecals.integer;
4886                         Cvar_SetValueQuick(&r_dynamic, 0);
4887                         Cvar_SetValueQuick(&r_drawparticles, 0);
4888                         Cvar_SetValueQuick(&r_drawdecals, 0);
4889                 }
4890         }
4891
4892         for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4893         {
4894                 p->rt_reflection = NULL;
4895                 p->rt_refraction = NULL;
4896                 p->rt_camera = NULL;
4897         }
4898
4899         // render views
4900         r_refdef.view = originalview;
4901         r_refdef.view.showdebug = false;
4902         r_refdef.view.width = r_fb.water.waterwidth;
4903         r_refdef.view.height = r_fb.water.waterheight;
4904         r_refdef.view.useclipplane = true;
4905         myview = r_refdef.view;
4906         r_fb.water.renderingscene = true;
4907         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4908         {
4909                 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4910                         continue;
4911
4912                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4913                 {
4914                         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);
4915                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4916                                 goto error;
4917                         r_refdef.view = myview;
4918                         Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4919                         Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4920                         if(r_water_scissormode.integer)
4921                         {
4922                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4923                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4924                                 {
4925                                         p->rt_reflection = NULL;
4926                                         p->rt_refraction = NULL;
4927                                         p->rt_camera = NULL;
4928                                         continue;
4929                                 }
4930                         }
4931
4932                         r_refdef.view.clipplane = p->plane;
4933                         // reflected view origin may be in solid, so don't cull with it
4934                         r_refdef.view.usevieworiginculling = false;
4935                         // reverse the cullface settings for this render
4936                         r_refdef.view.cullface_front = GL_FRONT;
4937                         r_refdef.view.cullface_back = GL_BACK;
4938                         // combined pvs (based on what can be seen from each surface center)
4939                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4940                         {
4941                                 r_refdef.view.usecustompvs = true;
4942                                 if (p->pvsvalid)
4943                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4944                                 else
4945                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4946                         }
4947
4948                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4949                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4950                         GL_ScissorTest(false);
4951                         R_ClearScreen(r_refdef.fogenabled);
4952                         GL_ScissorTest(true);
4953                         if(r_water_scissormode.integer & 2)
4954                                 R_View_UpdateWithScissor(myscissor);
4955                         else
4956                                 R_View_Update();
4957                         R_AnimCache_CacheVisibleEntities();
4958                         if(r_water_scissormode.integer & 1)
4959                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4960                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4961
4962                         r_fb.water.hideplayer = false;
4963                         p->rt_reflection = rt;
4964                 }
4965
4966                 // render the normal view scene and copy into texture
4967                 // (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)
4968                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
4969                 {
4970                         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);
4971                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4972                                 goto error;
4973                         r_refdef.view = myview;
4974                         if(r_water_scissormode.integer)
4975                         {
4976                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4977                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4978                                 {
4979                                         p->rt_reflection = NULL;
4980                                         p->rt_refraction = NULL;
4981                                         p->rt_camera = NULL;
4982                                         continue;
4983                                 }
4984                         }
4985
4986                         // combined pvs (based on what can be seen from each surface center)
4987                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4988                         {
4989                                 r_refdef.view.usecustompvs = true;
4990                                 if (p->pvsvalid)
4991                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4992                                 else
4993                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4994                         }
4995
4996                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
4997
4998                         r_refdef.view.clipplane = p->plane;
4999                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5000                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5001
5002                         if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
5003                         {
5004                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5005                                 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
5006                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5007                                 R_RenderView_UpdateViewVectors();
5008                                 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5009                                 {
5010                                         r_refdef.view.usecustompvs = true;
5011                                         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);
5012                                 }
5013                         }
5014
5015                         PlaneClassify(&r_refdef.view.clipplane);
5016
5017                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5018                         GL_ScissorTest(false);
5019                         R_ClearScreen(r_refdef.fogenabled);
5020                         GL_ScissorTest(true);
5021                         if(r_water_scissormode.integer & 2)
5022                                 R_View_UpdateWithScissor(myscissor);
5023                         else
5024                                 R_View_Update();
5025                         R_AnimCache_CacheVisibleEntities();
5026                         if(r_water_scissormode.integer & 1)
5027                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
5028                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5029
5030                         r_fb.water.hideplayer = false;
5031                         p->rt_refraction = rt;
5032                 }
5033                 else if (p->materialflags & MATERIALFLAG_CAMERA)
5034                 {
5035                         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);
5036                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5037                                 goto error;
5038                         r_refdef.view = myview;
5039
5040                         r_refdef.view.clipplane = p->plane;
5041                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5042                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5043
5044                         r_refdef.view.width = r_fb.water.camerawidth;
5045                         r_refdef.view.height = r_fb.water.cameraheight;
5046                         r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
5047                         r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
5048                         r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
5049                         r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
5050
5051                         if(p->camera_entity)
5052                         {
5053                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5054                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5055                         }
5056
5057                         // note: all of the view is used for displaying... so
5058                         // there is no use in scissoring
5059
5060                         // reverse the cullface settings for this render
5061                         r_refdef.view.cullface_front = GL_FRONT;
5062                         r_refdef.view.cullface_back = GL_BACK;
5063                         // also reverse the view matrix
5064                         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
5065                         R_RenderView_UpdateViewVectors();
5066                         if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5067                         {
5068                                 r_refdef.view.usecustompvs = true;
5069                                 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);
5070                         }
5071                         
5072                         // camera needs no clipplane
5073                         r_refdef.view.useclipplane = false;
5074                         // TODO: is the camera origin always valid?  if so we don't need to clear this
5075                         r_refdef.view.usevieworiginculling = false;
5076
5077                         PlaneClassify(&r_refdef.view.clipplane);
5078
5079                         r_fb.water.hideplayer = false;
5080
5081                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5082                         GL_ScissorTest(false);
5083                         R_ClearScreen(r_refdef.fogenabled);
5084                         GL_ScissorTest(true);
5085                         R_View_Update();
5086                         R_AnimCache_CacheVisibleEntities();
5087                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5088
5089                         r_fb.water.hideplayer = false;
5090                         p->rt_camera = rt;
5091                 }
5092
5093         }
5094         r_fb.water.renderingscene = false;
5095         r_refdef.view = originalview;
5096         R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5097         R_View_Update();
5098         R_AnimCache_CacheVisibleEntities();
5099         goto finish;
5100 error:
5101         r_refdef.view = originalview;
5102         r_fb.water.renderingscene = false;
5103         Cvar_SetValueQuick(&r_water, 0);
5104         Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed!  Turned off r_water.\n");
5105 finish:
5106         // lowquality hack, restore cvars
5107         if (qualityreduction > 0)
5108         {
5109                 if (qualityreduction >= 1)
5110                 {
5111                         Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5112                         Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5113                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5114                 }
5115                 if (qualityreduction >= 2)
5116                 {
5117                         Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5118                         Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5119                         Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5120                 }
5121         }
5122 }
5123
5124 static void R_Bloom_StartFrame(void)
5125 {
5126         int screentexturewidth, screentextureheight;
5127         textype_t textype = TEXTYPE_COLORBUFFER;
5128         double scale;
5129
5130         // clear the pointers to rendertargets from last frame as they're stale
5131         r_fb.rt_screen = NULL;
5132         r_fb.rt_bloom = NULL;
5133
5134         switch (vid.renderpath)
5135         {
5136         case RENDERPATH_GL32:
5137                 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5138                 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5139                 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5140                 break;
5141         case RENDERPATH_GLES2:
5142                 r_fb.usedepthtextures = false;
5143                 break;
5144         }
5145
5146         if (r_viewscale_fpsscaling.integer)
5147         {
5148                 double actualframetime;
5149                 double targetframetime;
5150                 double adjust;
5151                 actualframetime = r_refdef.lastdrawscreentime;
5152                 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5153                 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5154                 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5155                 if (r_viewscale_fpsscaling_stepsize.value > 0)
5156                 {
5157                         if (adjust > 0)
5158                                 adjust = floor(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5159                         else
5160                                 adjust = ceil(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5161                 }
5162                 viewscalefpsadjusted += adjust;
5163                 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5164         }
5165         else
5166                 viewscalefpsadjusted = 1.0f;
5167
5168         scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
5169         if (vid.samples)
5170                 scale *= sqrt(vid.samples); // supersampling
5171         scale = bound(0.03125f, scale, 4.0f);
5172         screentexturewidth = (int)ceil(r_refdef.view.width * scale);
5173         screentextureheight = (int)ceil(r_refdef.view.height * scale);
5174         screentexturewidth = bound(1, screentexturewidth, (int)vid.maxtexturesize_2d);
5175         screentextureheight = bound(1, screentextureheight, (int)vid.maxtexturesize_2d);
5176
5177         // set bloomwidth and bloomheight to the bloom resolution that will be
5178         // used (often less than the screen resolution for faster rendering)
5179         r_fb.bloomheight = bound(1, r_bloom_resolution.value * 0.75f, vid.height * 4);
5180         r_fb.bloomwidth = r_fb.bloomheight * vid.width / vid.height;
5181         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, vid.width * 4);
5182         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5183         r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5184
5185         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))
5186         {
5187                 Cvar_SetValueQuick(&r_bloom, 0);
5188                 Cvar_SetValueQuick(&r_motionblur, 0);
5189                 Cvar_SetValueQuick(&r_damageblur, 0);
5190         }
5191         if (!r_bloom.integer)
5192                 r_fb.bloomwidth = r_fb.bloomheight = 0;
5193
5194         // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5195         if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5196         {
5197                 if (r_fb.ghosttexture)
5198                         R_FreeTexture(r_fb.ghosttexture);
5199                 r_fb.ghosttexture = NULL;
5200
5201                 r_fb.screentexturewidth = screentexturewidth;
5202                 r_fb.screentextureheight = screentextureheight;
5203                 r_fb.textype = textype;
5204
5205                 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5206                 {
5207                         if (r_motionblur.value > 0 || r_damageblur.value > 0)
5208                                 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);
5209                         r_fb.ghosttexture_valid = false;
5210                 }
5211         }
5212
5213         r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5214
5215         r_refdef.view.clear = true;
5216 }
5217
5218 static void R_Bloom_MakeTexture(void)
5219 {
5220         int x, range, dir;
5221         float xoffset, yoffset, r, brighten;
5222         float colorscale = r_bloom_colorscale.value;
5223         r_viewport_t bloomviewport;
5224         r_rendertarget_t *prev, *cur;
5225         textype_t textype = r_fb.rt_screen->colortextype[0];
5226
5227         r_refdef.stats[r_stat_bloom]++;
5228
5229         R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5230
5231         // scale down screen texture to the bloom texture size
5232         CHECKGLERROR
5233         prev = r_fb.rt_screen;
5234         cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5235         R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5236         R_SetViewport(&bloomviewport);
5237         GL_CullFace(GL_NONE);
5238         GL_DepthTest(false);
5239         GL_BlendFunc(GL_ONE, GL_ZERO);
5240         GL_Color(colorscale, colorscale, colorscale, 1);
5241         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5242         // TODO: do boxfilter scale-down in shader?
5243         R_SetupShader_Generic(prev->colortexture[0], false, true, true);
5244         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5245         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5246         // we now have a properly scaled bloom image
5247
5248         // multiply bloom image by itself as many times as desired to darken it
5249         // TODO: if people actually use this it could be done more quickly in the previous shader pass
5250         for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5251         {
5252                 prev = cur;
5253                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5254                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5255                 x *= 2;
5256                 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5257                 if(x <= 2)
5258                         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0);
5259                 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5260                 GL_Color(1,1,1,1); // no fix factor supported here
5261                 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5262                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5263                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5264                 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5265         }
5266         CHECKGLERROR
5267
5268         range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5269         brighten = r_bloom_brighten.value;
5270         brighten = sqrt(brighten);
5271         if(range >= 1)
5272                 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5273
5274         for (dir = 0;dir < 2;dir++)
5275         {
5276                 prev = cur;
5277                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5278                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5279                 // blend on at multiple vertical offsets to achieve a vertical blur
5280                 // TODO: do offset blends using GLSL
5281                 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5282                 CHECKGLERROR
5283                 GL_BlendFunc(GL_ONE, GL_ZERO);
5284                 CHECKGLERROR
5285                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5286                 CHECKGLERROR
5287                 for (x = -range;x <= range;x++)
5288                 {
5289                         if (!dir){xoffset = 0;yoffset = x;}
5290                         else {xoffset = x;yoffset = 0;}
5291                         xoffset /= (float)prev->texturewidth;
5292                         yoffset /= (float)prev->textureheight;
5293                         // compute a texcoord array with the specified x and y offset
5294                         r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5295                         r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5296                         r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5297                         r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5298                         r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5299                         r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5300                         r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5301                         r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5302                         // this r value looks like a 'dot' particle, fading sharply to
5303                         // black at the edges
5304                         // (probably not realistic but looks good enough)
5305                         //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5306                         //r = brighten/(range*2+1);
5307                         r = brighten / (range * 2 + 1);
5308                         if(range >= 1)
5309                                 r *= (1 - x*x/(float)((range+1)*(range+1)));
5310                         if (r <= 0)
5311                                 continue;
5312                         CHECKGLERROR
5313                         GL_Color(r, r, r, 1);
5314                         CHECKGLERROR
5315                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5316                         CHECKGLERROR
5317                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5318                         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5319                         CHECKGLERROR
5320                         GL_BlendFunc(GL_ONE, GL_ONE);
5321                         CHECKGLERROR
5322                 }
5323         }
5324
5325         // now we have the bloom image, so keep track of it
5326         r_fb.rt_bloom = cur;
5327 }
5328
5329 static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5330 {
5331         dpuint64 permutation;
5332         float uservecs[4][4];
5333         rtexture_t *viewtexture;
5334         rtexture_t *bloomtexture;
5335
5336         R_EntityMatrix(&identitymatrix);
5337
5338         if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
5339         {
5340                 // declare variables
5341                 float blur_factor, blur_mouseaccel, blur_velocity;
5342                 static float blur_average; 
5343                 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5344
5345                 // set a goal for the factoring
5346                 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value) 
5347                         / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5348                 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value) 
5349                         / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5350                 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value) 
5351                         + (blur_mouseaccel * r_motionblur_mousefactor.value));
5352
5353                 // from the goal, pick an averaged value between goal and last value
5354                 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5355                 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5356
5357                 // enforce minimum amount of blur 
5358                 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5359
5360                 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5361
5362                 // calculate values into a standard alpha
5363                 cl.motionbluralpha = 1 - exp(-
5364                                 (
5365                                         (r_motionblur.value * blur_factor / 80)
5366                                         +
5367                                         (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5368                                 )
5369                                 /
5370                                 max(0.0001, cl.time - cl.oldtime) // fps independent
5371                                 );
5372
5373                 // randomization for the blur value to combat persistent ghosting
5374                 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5375                 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5376
5377                 // apply the blur
5378                 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5379                 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5380                 {
5381                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5382                         GL_Color(1, 1, 1, cl.motionbluralpha);
5383                         R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5384                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5385                         R_SetupShader_Generic(r_fb.ghosttexture, false, true, true);
5386                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5387                         r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5388                 }
5389
5390                 // updates old view angles for next pass
5391                 VectorCopy(cl.viewangles, blur_oldangles);
5392
5393                 // copy view into the ghost texture
5394                 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5395                 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5396                 r_fb.ghosttexture_valid = true;
5397         }
5398
5399         if (r_fb.bloomwidth)
5400         {
5401                 // make the bloom texture
5402                 R_Bloom_MakeTexture();
5403         }
5404
5405 #if _MSC_VER >= 1400
5406 #define sscanf sscanf_s
5407 #endif
5408         memset(uservecs, 0, sizeof(uservecs));
5409         if (r_glsl_postprocess_uservec1_enable.integer)
5410                 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5411         if (r_glsl_postprocess_uservec2_enable.integer)
5412                 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5413         if (r_glsl_postprocess_uservec3_enable.integer)
5414                 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5415         if (r_glsl_postprocess_uservec4_enable.integer)
5416                 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5417
5418         // render to the screen fbo
5419         R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5420         GL_Color(1, 1, 1, 1);
5421         GL_BlendFunc(GL_ONE, GL_ZERO);
5422
5423         viewtexture = r_fb.rt_screen->colortexture[0];
5424         bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5425
5426         if (r_rendertarget_debug.integer >= 0)
5427         {
5428                 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5429                 if (rt && rt->colortexture[0])
5430                 {
5431                         viewtexture = rt->colortexture[0];
5432                         bloomtexture = NULL;
5433                 }
5434         }
5435
5436         R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5437         switch(vid.renderpath)
5438         {
5439         case RENDERPATH_GL32:
5440         case RENDERPATH_GLES2:
5441                 permutation =
5442                         (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5443                         | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5444                         | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5445                         | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5446                         | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5447                 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5448                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First     , viewtexture);
5449                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second    , bloomtexture);
5450                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps       );
5451                 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]);
5452                 if (r_glsl_permutation->loc_PixelSize               >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize         , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5453                 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]);
5454                 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]);
5455                 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]);
5456                 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]);
5457                 if (r_glsl_permutation->loc_Saturation              >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation        , r_glsl_saturation.value);
5458                 if (r_glsl_permutation->loc_PixelToScreenTexCoord   >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
5459                 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);
5460                 if (r_glsl_permutation->loc_ColorFringe             >= 0) qglUniform1f(r_glsl_permutation->loc_ColorFringe, r_colorfringe.value );
5461                 break;
5462         }
5463         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5464         r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5465 }
5466
5467 matrix4x4_t r_waterscrollmatrix;
5468
5469 void R_UpdateFog(void)
5470 {
5471         // Nehahra fog
5472         if (gamemode == GAME_NEHAHRA)
5473         {
5474                 if (gl_fogenable.integer)
5475                 {
5476                         r_refdef.oldgl_fogenable = true;
5477                         r_refdef.fog_density = gl_fogdensity.value;
5478                         r_refdef.fog_red = gl_fogred.value;
5479                         r_refdef.fog_green = gl_foggreen.value;
5480                         r_refdef.fog_blue = gl_fogblue.value;
5481                         r_refdef.fog_alpha = 1;
5482                         r_refdef.fog_start = 0;
5483                         r_refdef.fog_end = gl_skyclip.value;
5484                         r_refdef.fog_height = 1<<30;
5485                         r_refdef.fog_fadedepth = 128;
5486                 }
5487                 else if (r_refdef.oldgl_fogenable)
5488                 {
5489                         r_refdef.oldgl_fogenable = false;
5490                         r_refdef.fog_density = 0;
5491                         r_refdef.fog_red = 0;
5492                         r_refdef.fog_green = 0;
5493                         r_refdef.fog_blue = 0;
5494                         r_refdef.fog_alpha = 0;
5495                         r_refdef.fog_start = 0;
5496                         r_refdef.fog_end = 0;
5497                         r_refdef.fog_height = 1<<30;
5498                         r_refdef.fog_fadedepth = 128;
5499                 }
5500         }
5501
5502         // fog parms
5503         r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5504         r_refdef.fog_start = max(0, r_refdef.fog_start);
5505         r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5506
5507         if (r_refdef.fog_density && r_drawfog.integer)
5508         {
5509                 r_refdef.fogenabled = true;
5510                 // this is the point where the fog reaches 0.9986 alpha, which we
5511                 // consider a good enough cutoff point for the texture
5512                 // (0.9986 * 256 == 255.6)
5513                 if (r_fog_exp2.integer)
5514                         r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5515                 else
5516                         r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5517                 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5518                 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5519                 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5520                 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5521                         R_BuildFogHeightTexture();
5522                 // fog color was already set
5523                 // update the fog texture
5524                 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)
5525                         R_BuildFogTexture();
5526                 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5527                 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5528         }
5529         else
5530                 r_refdef.fogenabled = false;
5531
5532         // fog color
5533         if (r_refdef.fog_density)
5534         {
5535                 r_refdef.fogcolor[0] = r_refdef.fog_red;
5536                 r_refdef.fogcolor[1] = r_refdef.fog_green;
5537                 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5538
5539                 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5540                 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5541                 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5542                 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5543
5544                 {
5545                         vec3_t fogvec;
5546                         VectorCopy(r_refdef.fogcolor, fogvec);
5547                         //   color.rgb *= ContrastBoost * SceneBrightness;
5548                         VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5549                         r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5550                         r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5551                         r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5552                 }
5553         }
5554 }
5555
5556 void R_UpdateVariables(void)
5557 {
5558         R_Textures_Frame();
5559
5560         r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5561
5562         r_refdef.farclip = r_farclip_base.value;
5563         if (r_refdef.scene.worldmodel)
5564                 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5565         r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5566
5567         if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5568                 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5569         r_refdef.polygonfactor = 0;
5570         r_refdef.polygonoffset = 0;
5571
5572         r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5573         r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5574         r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5575         r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5576         r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5577         if (r_refdef.scene.worldmodel)
5578         {
5579                 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5580         }
5581         if (r_showsurfaces.integer)
5582         {
5583                 r_refdef.scene.rtworld = false;
5584                 r_refdef.scene.rtworldshadows = false;
5585                 r_refdef.scene.rtdlight = false;
5586                 r_refdef.scene.rtdlightshadows = false;
5587                 r_refdef.scene.lightmapintensity = 0;
5588         }
5589
5590         r_gpuskeletal = false;
5591         switch(vid.renderpath)
5592         {
5593         case RENDERPATH_GL32:
5594                 r_gpuskeletal = r_glsl_skeletal.integer && !r_showsurfaces.integer;
5595         case RENDERPATH_GLES2:
5596                 if(!vid_gammatables_trivial)
5597                 {
5598                         if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5599                         {
5600                                 // build GLSL gamma texture
5601 #define RAMPWIDTH 256
5602                                 unsigned short ramp[RAMPWIDTH * 3];
5603                                 unsigned char rampbgr[RAMPWIDTH][4];
5604                                 int i;
5605
5606                                 r_texture_gammaramps_serial = vid_gammatables_serial;
5607
5608                                 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5609                                 for(i = 0; i < RAMPWIDTH; ++i)
5610                                 {
5611                                         rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5612                                         rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5613                                         rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5614                                         rampbgr[i][3] = 0;
5615                                 }
5616                                 if (r_texture_gammaramps)
5617                                 {
5618                                         R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1);
5619                                 }
5620                                 else
5621                                 {
5622                                         r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5623                                 }
5624                         }
5625                 }
5626                 else
5627                 {
5628                         // remove GLSL gamma texture
5629                 }
5630                 break;
5631         }
5632 }
5633
5634 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5635 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5636 /*
5637 ================
5638 R_SelectScene
5639 ================
5640 */
5641 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5642         if( scenetype != r_currentscenetype ) {
5643                 // store the old scenetype
5644                 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5645                 r_currentscenetype = scenetype;
5646                 // move in the new scene
5647                 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5648         }
5649 }
5650
5651 /*
5652 ================
5653 R_GetScenePointer
5654 ================
5655 */
5656 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5657 {
5658         // of course, we could also add a qboolean that provides a lock state and a ReleaseScenePointer function..
5659         if( scenetype == r_currentscenetype ) {
5660                 return &r_refdef.scene;
5661         } else {
5662                 return &r_scenes_store[ scenetype ];
5663         }
5664 }
5665
5666 static int R_SortEntities_Compare(const void *ap, const void *bp)
5667 {
5668         const entity_render_t *a = *(const entity_render_t **)ap;
5669         const entity_render_t *b = *(const entity_render_t **)bp;
5670
5671         // 1. compare model
5672         if(a->model < b->model)
5673                 return -1;
5674         if(a->model > b->model)
5675                 return +1;
5676
5677         // 2. compare skin
5678         // TODO possibly calculate the REAL skinnum here first using
5679         // skinscenes?
5680         if(a->skinnum < b->skinnum)
5681                 return -1;
5682         if(a->skinnum > b->skinnum)
5683                 return +1;
5684
5685         // everything we compared is equal
5686         return 0;
5687 }
5688 static void R_SortEntities(void)
5689 {
5690         // below or equal 2 ents, sorting never gains anything
5691         if(r_refdef.scene.numentities <= 2)
5692                 return;
5693         // sort
5694         qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5695 }
5696
5697 /*
5698 ================
5699 R_RenderView
5700 ================
5701 */
5702 extern cvar_t r_shadow_bouncegrid;
5703 extern cvar_t v_isometric;
5704 extern void V_MakeViewIsometric(void);
5705 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5706 {
5707         matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5708         int viewfbo = 0;
5709         rtexture_t *viewdepthtexture = NULL;
5710         rtexture_t *viewcolortexture = NULL;
5711         int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5712
5713         // finish any 2D rendering that was queued
5714         DrawQ_Finish();
5715
5716         if (r_timereport_active)
5717                 R_TimeReport("start");
5718         r_textureframe++; // used only by R_GetCurrentTexture
5719         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5720
5721         if(R_CompileShader_CheckStaticParms())
5722                 R_GLSL_Restart_f(&cmd_client);
5723
5724         if (!r_drawentities.integer)
5725                 r_refdef.scene.numentities = 0;
5726         else if (r_sortentities.integer)
5727                 R_SortEntities();
5728
5729         R_AnimCache_ClearCache();
5730
5731         /* adjust for stereo display */
5732         if(R_Stereo_Active())
5733         {
5734                 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);
5735                 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5736         }
5737
5738         if (r_refdef.view.isoverlay)
5739         {
5740                 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5741                 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5742                 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5743                 R_TimeReport("depthclear");
5744
5745                 r_refdef.view.showdebug = false;
5746
5747                 r_fb.water.enabled = false;
5748                 r_fb.water.numwaterplanes = 0;
5749
5750                 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5751
5752                 r_refdef.view.matrix = originalmatrix;
5753
5754                 CHECKGLERROR
5755                 return;
5756         }
5757
5758         if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5759         {
5760                 r_refdef.view.matrix = originalmatrix;
5761                 return;
5762         }
5763
5764         r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5765         if (v_isometric.integer && r_refdef.view.ismain)
5766                 V_MakeViewIsometric();
5767
5768         r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5769
5770         if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5771                 // in sRGB fallback, behave similar to true sRGB: convert this
5772                 // value from linear to sRGB
5773                 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5774
5775         R_RenderView_UpdateViewVectors();
5776
5777         R_Shadow_UpdateWorldLightSelection();
5778
5779         // this will set up r_fb.rt_screen
5780         R_Bloom_StartFrame();
5781
5782         // apply bloom brightness offset
5783         if(r_fb.rt_bloom)
5784                 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5785
5786         // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5787         if (r_fb.rt_screen)
5788         {
5789                 viewfbo = r_fb.rt_screen->fbo;
5790                 viewdepthtexture = r_fb.rt_screen->depthtexture;
5791                 viewcolortexture = r_fb.rt_screen->colortexture[0];
5792                 viewx = 0;
5793                 viewy = 0;
5794                 viewwidth = r_fb.rt_screen->texturewidth;
5795                 viewheight = r_fb.rt_screen->textureheight;
5796         }
5797
5798         R_Water_StartFrame(viewwidth, viewheight);
5799
5800         CHECKGLERROR
5801         if (r_timereport_active)
5802                 R_TimeReport("viewsetup");
5803
5804         R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5805
5806         // clear the whole fbo every frame - otherwise the driver will consider
5807         // it to be an inter-frame texture and stall in multi-gpu configurations
5808         if (r_fb.rt_screen)
5809                 GL_ScissorTest(false);
5810         R_ClearScreen(r_refdef.fogenabled);
5811         if (r_timereport_active)
5812                 R_TimeReport("viewclear");
5813
5814         r_refdef.view.clear = true;
5815
5816         r_refdef.view.showdebug = true;
5817
5818         R_View_Update();
5819         if (r_timereport_active)
5820                 R_TimeReport("visibility");
5821
5822         R_AnimCache_CacheVisibleEntities();
5823         if (r_timereport_active)
5824                 R_TimeReport("animcache");
5825
5826         R_Shadow_UpdateBounceGridTexture();
5827         // R_Shadow_UpdateBounceGridTexture called R_TimeReport a few times internally, so we don't need to do that here.
5828
5829         r_fb.water.numwaterplanes = 0;
5830         if (r_fb.water.enabled)
5831                 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5832
5833         // for the actual view render we use scissoring a fair amount, so scissor
5834         // test needs to be on
5835         if (r_fb.rt_screen)
5836                 GL_ScissorTest(true);
5837         GL_Scissor(viewx, viewy, viewwidth, viewheight);
5838         R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5839         r_fb.water.numwaterplanes = 0;
5840
5841         // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5842         GL_ScissorTest(false);
5843
5844         R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
5845         if (r_timereport_active)
5846                 R_TimeReport("blendview");
5847
5848         r_refdef.view.matrix = originalmatrix;
5849
5850         CHECKGLERROR
5851
5852         // go back to 2d rendering
5853         DrawQ_Start();
5854 }
5855
5856 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5857 {
5858         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5859         {
5860                 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5861                 if (r_timereport_active)
5862                         R_TimeReport("waterworld");
5863         }
5864
5865         // don't let sound skip if going slow
5866         if (r_refdef.scene.extraupdate)
5867                 S_ExtraUpdate ();
5868
5869         R_DrawModelsAddWaterPlanes();
5870         if (r_timereport_active)
5871                 R_TimeReport("watermodels");
5872
5873         if (r_fb.water.numwaterplanes)
5874         {
5875                 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5876                 if (r_timereport_active)
5877                         R_TimeReport("waterscenes");
5878         }
5879 }
5880
5881 extern cvar_t cl_locs_show;
5882 static void R_DrawLocs(void);
5883 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5884 static void R_DrawModelDecals(void);
5885 extern qboolean r_shadow_usingdeferredprepass;
5886 extern int r_shadow_shadowmapatlas_modelshadows_size;
5887 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5888 {
5889         qboolean shadowmapping = false;
5890
5891         if (r_timereport_active)
5892                 R_TimeReport("beginscene");
5893
5894         r_refdef.stats[r_stat_renders]++;
5895
5896         R_UpdateFog();
5897
5898         // don't let sound skip if going slow
5899         if (r_refdef.scene.extraupdate)
5900                 S_ExtraUpdate ();
5901
5902         R_MeshQueue_BeginScene();
5903
5904         R_SkyStartFrame();
5905
5906         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);
5907
5908         if (r_timereport_active)
5909                 R_TimeReport("skystartframe");
5910
5911         if (cl.csqc_vidvars.drawworld)
5912         {
5913                 // don't let sound skip if going slow
5914                 if (r_refdef.scene.extraupdate)
5915                         S_ExtraUpdate ();
5916
5917                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5918                 {
5919                         r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5920                         if (r_timereport_active)
5921                                 R_TimeReport("worldsky");
5922                 }
5923
5924                 if (R_DrawBrushModelsSky() && r_timereport_active)
5925                         R_TimeReport("bmodelsky");
5926
5927                 if (skyrendermasked && skyrenderlater)
5928                 {
5929                         // we have to force off the water clipping plane while rendering sky
5930                         R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5931                         R_Sky();
5932                         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5933                         if (r_timereport_active)
5934                                 R_TimeReport("sky");
5935                 }
5936         }
5937
5938         // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5939         r_shadow_viewfbo = viewfbo;
5940         r_shadow_viewdepthtexture = viewdepthtexture;
5941         r_shadow_viewcolortexture = viewcolortexture;
5942         r_shadow_viewx = viewx;
5943         r_shadow_viewy = viewy;
5944         r_shadow_viewwidth = viewwidth;
5945         r_shadow_viewheight = viewheight;
5946
5947         R_Shadow_PrepareModelShadows();
5948         R_Shadow_PrepareLights();
5949         if (r_timereport_active)
5950                 R_TimeReport("preparelights");
5951
5952         // render all the shadowmaps that will be used for this view
5953         shadowmapping = R_Shadow_ShadowMappingEnabled();
5954         if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
5955         {
5956                 R_Shadow_DrawShadowMaps();
5957                 if (r_timereport_active)
5958                         R_TimeReport("shadowmaps");
5959         }
5960
5961         // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
5962         if (r_shadow_usingdeferredprepass)
5963                 R_Shadow_DrawPrepass();
5964
5965         // now we begin the forward pass of the view render
5966         if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
5967         {
5968                 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
5969                 if (r_timereport_active)
5970                         R_TimeReport("worlddepth");
5971         }
5972         if (r_depthfirst.integer >= 2)
5973         {
5974                 R_DrawModelsDepth();
5975                 if (r_timereport_active)
5976                         R_TimeReport("modeldepth");
5977         }
5978
5979         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
5980         {
5981                 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
5982                 if (r_timereport_active)
5983                         R_TimeReport("world");
5984         }
5985
5986         // don't let sound skip if going slow
5987         if (r_refdef.scene.extraupdate)
5988                 S_ExtraUpdate ();
5989
5990         R_DrawModels();
5991         if (r_timereport_active)
5992                 R_TimeReport("models");
5993
5994         // don't let sound skip if going slow
5995         if (r_refdef.scene.extraupdate)
5996                 S_ExtraUpdate ();
5997
5998         if (!r_shadow_usingdeferredprepass)
5999         {
6000                 R_Shadow_DrawLights();
6001                 if (r_timereport_active)
6002                         R_TimeReport("rtlights");
6003         }
6004
6005         // don't let sound skip if going slow
6006         if (r_refdef.scene.extraupdate)
6007                 S_ExtraUpdate ();
6008
6009         if (cl.csqc_vidvars.drawworld)
6010         {
6011                 R_DrawModelDecals();
6012                 if (r_timereport_active)
6013                         R_TimeReport("modeldecals");
6014
6015                 R_DrawParticles();
6016                 if (r_timereport_active)
6017                         R_TimeReport("particles");
6018
6019                 R_DrawExplosions();
6020                 if (r_timereport_active)
6021                         R_TimeReport("explosions");
6022         }
6023
6024         if (r_refdef.view.showdebug)
6025         {
6026                 if (cl_locs_show.integer)
6027                 {
6028                         R_DrawLocs();
6029                         if (r_timereport_active)
6030                                 R_TimeReport("showlocs");
6031                 }
6032
6033                 if (r_drawportals.integer)
6034                 {
6035                         R_DrawPortals();
6036                         if (r_timereport_active)
6037                                 R_TimeReport("portals");
6038                 }
6039
6040                 if (r_showbboxes_client.value > 0)
6041                 {
6042                         R_DrawEntityBBoxes(CLVM_prog);
6043                         if (r_timereport_active)
6044                                 R_TimeReport("clbboxes");
6045                 }
6046                 if (r_showbboxes.value > 0)
6047                 {
6048                         R_DrawEntityBBoxes(SVVM_prog);
6049                         if (r_timereport_active)
6050                                 R_TimeReport("svbboxes");
6051                 }
6052         }
6053
6054         if (r_transparent.integer)
6055         {
6056                 R_MeshQueue_RenderTransparent();
6057                 if (r_timereport_active)
6058                         R_TimeReport("drawtrans");
6059         }
6060
6061         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))
6062         {
6063                 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
6064                 if (r_timereport_active)
6065                         R_TimeReport("worlddebug");
6066                 R_DrawModelsDebug();
6067                 if (r_timereport_active)
6068                         R_TimeReport("modeldebug");
6069         }
6070
6071         if (cl.csqc_vidvars.drawworld)
6072         {
6073                 R_Shadow_DrawCoronas();
6074                 if (r_timereport_active)
6075                         R_TimeReport("coronas");
6076         }
6077
6078         // don't let sound skip if going slow
6079         if (r_refdef.scene.extraupdate)
6080                 S_ExtraUpdate ();
6081 }
6082
6083 static const unsigned short bboxelements[36] =
6084 {
6085         5, 1, 3, 5, 3, 7,
6086         6, 2, 0, 6, 0, 4,
6087         7, 3, 2, 7, 2, 6,
6088         4, 0, 1, 4, 1, 5,
6089         4, 5, 7, 4, 7, 6,
6090         1, 0, 2, 1, 2, 3,
6091 };
6092
6093 #define BBOXEDGES 13
6094 static const float bboxedges[BBOXEDGES][6] = 
6095 {
6096         // whole box
6097         { 0, 0, 0, 1, 1, 1 },
6098         // bottom edges
6099         { 0, 0, 0, 0, 1, 0 },
6100         { 0, 0, 0, 1, 0, 0 },
6101         { 0, 1, 0, 1, 1, 0 },
6102         { 1, 0, 0, 1, 1, 0 },
6103         // top edges
6104         { 0, 0, 1, 0, 1, 1 },
6105         { 0, 0, 1, 1, 0, 1 },
6106         { 0, 1, 1, 1, 1, 1 },
6107         { 1, 0, 1, 1, 1, 1 },
6108         // vertical edges
6109         { 0, 0, 0, 0, 0, 1 },
6110         { 1, 0, 0, 1, 0, 1 },
6111         { 0, 1, 0, 0, 1, 1 },
6112         { 1, 1, 0, 1, 1, 1 },
6113 };
6114
6115 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6116 {
6117         int numvertices = BBOXEDGES * 8;
6118         float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6119         int numtriangles = BBOXEDGES * 12;
6120         unsigned short elements[BBOXEDGES * 36];
6121         int i, edge;
6122         float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6123
6124         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6125
6126         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6127         GL_DepthMask(false);
6128         GL_DepthRange(0, 1);
6129         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6130
6131         for (edge = 0; edge < BBOXEDGES; edge++)
6132         {
6133                 for (i = 0; i < 3; i++)
6134                 {
6135                         edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6136                         edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6137                 }
6138                 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6139                 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6140                 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6141                 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6142                 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6143                 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6144                 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6145                 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6146                 for (i = 0; i < 36; i++)
6147                         elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6148         }
6149         R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6150         if (r_refdef.fogenabled)
6151         {
6152                 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6153                 {
6154                         f1 = RSurf_FogVertex(v);
6155                         f2 = 1 - f1;
6156                         c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6157                         c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6158                         c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6159                 }
6160         }
6161         R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6162         R_Mesh_ResetTextureState();
6163         R_SetupShader_Generic_NoTexture(false, false);
6164         R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6165 }
6166
6167 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6168 {
6169         // hacky overloading of the parameters
6170         prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6171         int i;
6172         float color[4];
6173         prvm_edict_t *edict;
6174
6175         GL_CullFace(GL_NONE);
6176         R_SetupShader_Generic_NoTexture(false, false);
6177
6178         for (i = 0;i < numsurfaces;i++)
6179         {
6180                 edict = PRVM_EDICT_NUM(surfacelist[i]);
6181                 switch ((int)PRVM_serveredictfloat(edict, solid))
6182                 {
6183                         case SOLID_NOT:      Vector4Set(color, 1, 1, 1, 0.05);break;
6184                         case SOLID_TRIGGER:  Vector4Set(color, 1, 0, 1, 0.10);break;
6185                         case SOLID_BBOX:     Vector4Set(color, 0, 1, 0, 0.10);break;
6186                         case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6187                         case SOLID_BSP:      Vector4Set(color, 0, 0, 1, 0.05);break;
6188                         case SOLID_CORPSE:   Vector4Set(color, 1, 0.5, 0, 0.05);break;
6189                         default:             Vector4Set(color, 0, 0, 0, 0.50);break;
6190                 }
6191                 if (prog == CLVM_prog)
6192                         color[3] *= r_showbboxes_client.value;
6193                 else
6194                         color[3] *= r_showbboxes.value;
6195                 color[3] = bound(0, color[3], 1);
6196                 GL_DepthTest(!r_showdisabledepthtest.integer);
6197                 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6198         }
6199 }
6200
6201 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6202 {
6203         int i;
6204         prvm_edict_t *edict;
6205         vec3_t center;
6206
6207         if (prog == NULL)
6208                 return;
6209
6210         for (i = 0; i < prog->num_edicts; i++)
6211         {
6212                 edict = PRVM_EDICT_NUM(i);
6213                 if (edict->priv.server->free)
6214                         continue;
6215                 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6216                 if (PRVM_gameedictedict(edict, tag_entity) != 0)
6217                         continue;
6218                 if (prog == SVVM_prog && PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6219                         continue;
6220                 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6221                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6222         }
6223 }
6224
6225 static const int nomodelelement3i[24] =
6226 {
6227         5, 2, 0,
6228         5, 1, 2,
6229         5, 0, 3,
6230         5, 3, 1,
6231         0, 2, 4,
6232         2, 1, 4,
6233         3, 0, 4,
6234         1, 3, 4
6235 };
6236
6237 static const unsigned short nomodelelement3s[24] =
6238 {
6239         5, 2, 0,
6240         5, 1, 2,
6241         5, 0, 3,
6242         5, 3, 1,
6243         0, 2, 4,
6244         2, 1, 4,
6245         3, 0, 4,
6246         1, 3, 4
6247 };
6248
6249 static const float nomodelvertex3f[6*3] =
6250 {
6251         -16,   0,   0,
6252          16,   0,   0,
6253           0, -16,   0,
6254           0,  16,   0,
6255           0,   0, -16,
6256           0,   0,  16
6257 };
6258
6259 static const float nomodelcolor4f[6*4] =
6260 {
6261         0.0f, 0.0f, 0.5f, 1.0f,
6262         0.0f, 0.0f, 0.5f, 1.0f,
6263         0.0f, 0.5f, 0.0f, 1.0f,
6264         0.0f, 0.5f, 0.0f, 1.0f,
6265         0.5f, 0.0f, 0.0f, 1.0f,
6266         0.5f, 0.0f, 0.0f, 1.0f
6267 };
6268
6269 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6270 {
6271         int i;
6272         float f1, f2, *c;
6273         float color4f[6*4];
6274
6275         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);
6276
6277         // this is only called once per entity so numsurfaces is always 1, and
6278         // surfacelist is always {0}, so this code does not handle batches
6279
6280         if (rsurface.ent_flags & RENDER_ADDITIVE)
6281         {
6282                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6283                 GL_DepthMask(false);
6284         }
6285         else if (ent->alpha < 1)
6286         {
6287                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6288                 GL_DepthMask(false);
6289         }
6290         else
6291         {
6292                 GL_BlendFunc(GL_ONE, GL_ZERO);
6293                 GL_DepthMask(true);
6294         }
6295         GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6296         GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6297         GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6298         GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6299         memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6300         for (i = 0, c = color4f;i < 6;i++, c += 4)
6301         {
6302                 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6303                 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6304                 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6305                 c[3] *= ent->alpha;
6306         }
6307         if (r_refdef.fogenabled)
6308         {
6309                 for (i = 0, c = color4f;i < 6;i++, c += 4)
6310                 {
6311                         f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6312                         f2 = 1 - f1;
6313                         c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6314                         c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6315                         c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6316                 }
6317         }
6318 //      R_Mesh_ResetTextureState();
6319         R_SetupShader_Generic_NoTexture(false, false);
6320         R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6321         R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6322 }
6323
6324 void R_DrawNoModel(entity_render_t *ent)
6325 {
6326         vec3_t org;
6327         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6328         if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6329                 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6330         else
6331                 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6332 }
6333
6334 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6335 {
6336         vec3_t right1, right2, diff, normal;
6337
6338         VectorSubtract (org2, org1, normal);
6339
6340         // calculate 'right' vector for start
6341         VectorSubtract (r_refdef.view.origin, org1, diff);
6342         CrossProduct (normal, diff, right1);
6343         VectorNormalize (right1);
6344
6345         // calculate 'right' vector for end
6346         VectorSubtract (r_refdef.view.origin, org2, diff);
6347         CrossProduct (normal, diff, right2);
6348         VectorNormalize (right2);
6349
6350         vert[ 0] = org1[0] + width * right1[0];
6351         vert[ 1] = org1[1] + width * right1[1];
6352         vert[ 2] = org1[2] + width * right1[2];
6353         vert[ 3] = org1[0] - width * right1[0];
6354         vert[ 4] = org1[1] - width * right1[1];
6355         vert[ 5] = org1[2] - width * right1[2];
6356         vert[ 6] = org2[0] - width * right2[0];
6357         vert[ 7] = org2[1] - width * right2[1];
6358         vert[ 8] = org2[2] - width * right2[2];
6359         vert[ 9] = org2[0] + width * right2[0];
6360         vert[10] = org2[1] + width * right2[1];
6361         vert[11] = org2[2] + width * right2[2];
6362 }
6363
6364 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)
6365 {
6366         vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6367         vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6368         vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6369         vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6370         vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6371         vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6372         vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6373         vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6374         vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6375         vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6376         vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6377         vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6378 }
6379
6380 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6381 {
6382         int i;
6383         float *vertex3f;
6384         float v[3];
6385         VectorSet(v, x, y, z);
6386         for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6387                 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6388                         break;
6389         if (i == mesh->numvertices)
6390         {
6391                 if (mesh->numvertices < mesh->maxvertices)
6392                 {
6393                         VectorCopy(v, vertex3f);
6394                         mesh->numvertices++;
6395                 }
6396                 return mesh->numvertices;
6397         }
6398         else
6399                 return i;
6400 }
6401
6402 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6403 {
6404         int i;
6405         int *e, element[3];
6406         element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6407         element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6408         e = mesh->element3i + mesh->numtriangles * 3;
6409         for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6410         {
6411                 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6412                 if (mesh->numtriangles < mesh->maxtriangles)
6413                 {
6414                         *e++ = element[0];
6415                         *e++ = element[1];
6416                         *e++ = element[2];
6417                         mesh->numtriangles++;
6418                 }
6419                 element[1] = element[2];
6420         }
6421 }
6422
6423 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6424 {
6425         int i;
6426         int *e, element[3];
6427         element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6428         element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6429         e = mesh->element3i + mesh->numtriangles * 3;
6430         for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6431         {
6432                 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6433                 if (mesh->numtriangles < mesh->maxtriangles)
6434                 {
6435                         *e++ = element[0];
6436                         *e++ = element[1];
6437                         *e++ = element[2];
6438                         mesh->numtriangles++;
6439                 }
6440                 element[1] = element[2];
6441         }
6442 }
6443
6444 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6445 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6446 {
6447         int planenum, planenum2;
6448         int w;
6449         int tempnumpoints;
6450         mplane_t *plane, *plane2;
6451         double maxdist;
6452         double temppoints[2][256*3];
6453         // figure out how large a bounding box we need to properly compute this brush
6454         maxdist = 0;
6455         for (w = 0;w < numplanes;w++)
6456                 maxdist = max(maxdist, fabs(planes[w].dist));
6457         // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6458         maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6459         for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6460         {
6461                 w = 0;
6462                 tempnumpoints = 4;
6463                 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6464                 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6465                 {
6466                         if (planenum2 == planenum)
6467                                 continue;
6468                         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);
6469                         w = !w;
6470                 }
6471                 if (tempnumpoints < 3)
6472                         continue;
6473                 // generate elements forming a triangle fan for this polygon
6474                 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6475         }
6476 }
6477
6478 static qboolean R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6479 {
6480         if(parms[0] == 0 && parms[1] == 0)
6481                 return false;
6482         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6483                 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6484                         return false;
6485         return true;
6486 }
6487
6488 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6489 {
6490         double index, f;
6491         index = parms[2] + rsurface.shadertime * parms[3];
6492         index -= floor(index);
6493         switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6494         {
6495         default:
6496         case Q3WAVEFUNC_NONE:
6497         case Q3WAVEFUNC_NOISE:
6498         case Q3WAVEFUNC_COUNT:
6499                 f = 0;
6500                 break;
6501         case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6502         case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6503         case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6504         case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6505         case Q3WAVEFUNC_TRIANGLE:
6506                 index *= 4;
6507                 f = index - floor(index);
6508                 if (index < 1)
6509                 {
6510                         // f = f;
6511                 }
6512                 else if (index < 2)
6513                         f = 1 - f;
6514                 else if (index < 3)
6515                         f = -f;
6516                 else
6517                         f = -(1 - f);
6518                 break;
6519         }
6520         f = parms[0] + parms[1] * f;
6521         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6522                 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6523         return (float) f;
6524 }
6525
6526 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6527 {
6528         int w, h, idx;
6529         float shadertime;
6530         float f;
6531         float offsetd[2];
6532         float tcmat[12];
6533         matrix4x4_t matrix, temp;
6534         // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6535         // it's better to have one huge fixup every 9 hours than gradual
6536         // degradation over time which looks consistently bad after many hours.
6537         //
6538         // tcmod scroll in particular suffers from this degradation which can't be
6539         // effectively worked around even with floor() tricks because we don't
6540         // know if tcmod scroll is the last tcmod being applied, and for clampmap
6541         // a workaround involving floor() would be incorrect anyway...
6542         shadertime = rsurface.shadertime;
6543         if (shadertime >= 32768.0f)
6544                 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6545         switch(tcmod->tcmod)
6546         {
6547                 case Q3TCMOD_COUNT:
6548                 case Q3TCMOD_NONE:
6549                         if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6550                                 matrix = r_waterscrollmatrix;
6551                         else
6552                                 matrix = identitymatrix;
6553                         break;
6554                 case Q3TCMOD_ENTITYTRANSLATE:
6555                         // this is used in Q3 to allow the gamecode to control texcoord
6556                         // scrolling on the entity, which is not supported in darkplaces yet.
6557                         Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6558                         break;
6559                 case Q3TCMOD_ROTATE:
6560                         Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6561                         Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6562                         Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6563                         break;
6564                 case Q3TCMOD_SCALE:
6565                         Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6566                         break;
6567                 case Q3TCMOD_SCROLL:
6568                         // this particular tcmod is a "bug for bug" compatible one with regards to
6569                         // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6570                         // specifically did the wrapping and so we must mimic that...
6571                         offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6572                         offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6573                         Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6574                         break;
6575                 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6576                         w = (int) tcmod->parms[0];
6577                         h = (int) tcmod->parms[1];
6578                         f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6579                         f = f - floor(f);
6580                         idx = (int) floor(f * w * h);
6581                         Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6582                         break;
6583                 case Q3TCMOD_STRETCH:
6584                         f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6585                         Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6586                         break;
6587                 case Q3TCMOD_TRANSFORM:
6588                         VectorSet(tcmat +  0, tcmod->parms[0], tcmod->parms[1], 0);
6589                         VectorSet(tcmat +  3, tcmod->parms[2], tcmod->parms[3], 0);
6590                         VectorSet(tcmat +  6, 0                   , 0                , 1);
6591                         VectorSet(tcmat +  9, tcmod->parms[4], tcmod->parms[5], 0);
6592                         Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6593                         break;
6594                 case Q3TCMOD_TURBULENT:
6595                         // this is handled in the RSurf_PrepareVertices function
6596                         matrix = identitymatrix;
6597                         break;
6598         }
6599         temp = *texmatrix;
6600         Matrix4x4_Concat(texmatrix, &matrix, &temp);
6601 }
6602
6603 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6604 {
6605         int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6606         char name[MAX_QPATH];
6607         skinframe_t *skinframe;
6608         unsigned char pixels[296*194];
6609         strlcpy(cache->name, skinname, sizeof(cache->name));
6610         dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6611         if (developer_loading.integer)
6612                 Con_Printf("loading %s\n", name);
6613         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6614         if (!skinframe || !skinframe->base)
6615         {
6616                 unsigned char *f;
6617                 fs_offset_t filesize;
6618                 skinframe = NULL;
6619                 f = FS_LoadFile(name, tempmempool, true, &filesize);
6620                 if (f)
6621                 {
6622                         if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6623                                 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6624                         Mem_Free(f);
6625                 }
6626         }
6627         cache->skinframe = skinframe;
6628 }
6629
6630 texture_t *R_GetCurrentTexture(texture_t *t)
6631 {
6632         int i, q;
6633         const entity_render_t *ent = rsurface.entity;
6634         dp_model_t *model = ent->model; // when calling this, ent must not be NULL
6635         q3shaderinfo_layer_tcmod_t *tcmod;
6636         float specularscale = 0.0f;
6637
6638         if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6639                 return t->currentframe;
6640         t->update_lastrenderframe = r_textureframe;
6641         t->update_lastrenderentity = (void *)ent;
6642
6643         if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6644                 t->camera_entity = ent->entitynumber;
6645         else
6646                 t->camera_entity = 0;
6647
6648         // switch to an alternate material if this is a q1bsp animated material
6649         {
6650                 texture_t *texture = t;
6651                 int s = rsurface.ent_skinnum;
6652                 if ((unsigned int)s >= (unsigned int)model->numskins)
6653                         s = 0;
6654                 if (model->skinscenes)
6655                 {
6656                         if (model->skinscenes[s].framecount > 1)
6657                                 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6658                         else
6659                                 s = model->skinscenes[s].firstframe;
6660                 }
6661                 if (s > 0)
6662                         t = t + s * model->num_surfaces;
6663                 if (t->animated)
6664                 {
6665                         // use an alternate animation if the entity's frame is not 0,
6666                         // and only if the texture has an alternate animation
6667                         if (t->animated == 2) // q2bsp
6668                                 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6669                         else if (rsurface.ent_alttextures && t->anim_total[1])
6670                                 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6671                         else
6672                                 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6673                 }
6674                 texture->currentframe = t;
6675         }
6676
6677         // update currentskinframe to be a qw skin or animation frame
6678         if (rsurface.ent_qwskin >= 0)
6679         {
6680                 i = rsurface.ent_qwskin;
6681                 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6682                 {
6683                         r_qwskincache_size = cl.maxclients;
6684                         if (r_qwskincache)
6685                                 Mem_Free(r_qwskincache);
6686                         r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6687                 }
6688                 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6689                         R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6690                 t->currentskinframe = r_qwskincache[i].skinframe;
6691                 if (t->materialshaderpass && t->currentskinframe == NULL)
6692                         t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6693         }
6694         else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6695                 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6696         if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6697                 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6698
6699         t->currentmaterialflags = t->basematerialflags;
6700         t->currentalpha = rsurface.entity->alpha * t->basealpha;
6701         if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_water.integer || r_novis.integer || r_trippy.integer))
6702                 t->currentalpha *= r_wateralpha.value;
6703         if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6704                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6705         if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6706                 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6707
6708         // decide on which type of lighting to use for this surface
6709         if (rsurface.entity->render_modellight_forced)
6710                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6711         if (rsurface.entity->render_rtlight_disabled)
6712                 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6713         if (rsurface.entity->render_lightgrid)
6714                 t->currentmaterialflags |= MATERIALFLAG_LIGHTGRID;
6715         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6716         {
6717                 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6718                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NORTLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6719                 for (q = 0; q < 3; q++)
6720                 {
6721                         t->render_glowmod[q] = rsurface.entity->glowmod[q];
6722                         t->render_modellight_lightdir[q] = q == 2;
6723                         t->render_modellight_ambient[q] = 1;
6724                         t->render_modellight_diffuse[q] = 0;
6725                         t->render_modellight_specular[q] = 0;
6726                         t->render_lightmap_ambient[q] = 0;
6727                         t->render_lightmap_diffuse[q] = 0;
6728                         t->render_lightmap_specular[q] = 0;
6729                         t->render_rtlight_diffuse[q] = 0;
6730                         t->render_rtlight_specular[q] = 0;
6731                 }
6732         }
6733         else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6734         {
6735                 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6736                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6737                 for (q = 0; q < 3; q++)
6738                 {
6739                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6740                         t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6741                         t->render_modellight_lightdir[q] = q == 2;
6742                         t->render_modellight_diffuse[q] = 0;
6743                         t->render_modellight_specular[q] = 0;
6744                         t->render_lightmap_ambient[q] = 0;
6745                         t->render_lightmap_diffuse[q] = 0;
6746                         t->render_lightmap_specular[q] = 0;
6747                         t->render_rtlight_diffuse[q] = 0;
6748                         t->render_rtlight_specular[q] = 0;
6749                 }
6750         }
6751         else if (t->currentmaterialflags & MATERIALFLAG_LIGHTGRID)
6752         {
6753                 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6754                 for (q = 0; q < 3; q++)
6755                 {
6756                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6757                         t->render_modellight_lightdir[q] = q == 2;
6758                         t->render_modellight_ambient[q] = 0;
6759                         t->render_modellight_diffuse[q] = 0;
6760                         t->render_modellight_specular[q] = 0;
6761                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6762                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6763                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6764                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6765                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6766                 }
6767         }
6768         else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6769         {
6770                 // ambient + single direction light (modellight)
6771                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6772                 for (q = 0; q < 3; q++)
6773                 {
6774                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6775                         t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6776                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6777                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6778                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6779                         t->render_lightmap_ambient[q] = 0;
6780                         t->render_lightmap_diffuse[q] = 0;
6781                         t->render_lightmap_specular[q] = 0;
6782                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6783                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6784                 }
6785         }
6786         else
6787         {
6788                 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6789                 for (q = 0; q < 3; q++)
6790                 {
6791                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6792                         t->render_modellight_lightdir[q] = q == 2;
6793                         t->render_modellight_ambient[q] = 0;
6794                         t->render_modellight_diffuse[q] = 0;
6795                         t->render_modellight_specular[q] = 0;
6796                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6797                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6798                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6799                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6800                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6801                 }
6802         }
6803
6804         if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6805         {
6806                 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6807                 // attribute, we punt it to the lightmap path and hope for the best,
6808                 // but lighting doesn't work.
6809                 //
6810                 // FIXME: this is fine for effects but CSQC polygons should be subject
6811                 // to lighting.
6812                 t->currentmaterialflags &= ~(MATERIALFLAG_MODELLIGHT | MATERIALFLAG_LIGHTGRID);
6813                 for (q = 0; q < 3; q++)
6814                 {
6815                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6816                         t->render_modellight_lightdir[q] = q == 2;
6817                         t->render_modellight_ambient[q] = 0;
6818                         t->render_modellight_diffuse[q] = 0;
6819                         t->render_modellight_specular[q] = 0;
6820                         t->render_lightmap_ambient[q] = 0;
6821                         t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6822                         t->render_lightmap_specular[q] = 0;
6823                         t->render_rtlight_diffuse[q] = 0;
6824                         t->render_rtlight_specular[q] = 0;
6825                 }
6826         }
6827
6828         for (q = 0; q < 3; q++)
6829         {
6830                 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6831                 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6832         }
6833
6834         if (rsurface.ent_flags & RENDER_ADDITIVE)
6835                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6836         else if (t->currentalpha < 1)
6837                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6838         // LadyHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6839         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6840                 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6841         if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6842                 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6843         if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6844                 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6845         if (t->backgroundshaderpass)
6846                 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6847         if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6848         {
6849                 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6850                         t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6851         }
6852         else
6853                 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6854         if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6855         {
6856                 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6857                 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6858         }
6859         if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6860                 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6861
6862         // there is no tcmod
6863         if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6864         {
6865                 t->currenttexmatrix = r_waterscrollmatrix;
6866                 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6867         }
6868         else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6869         {
6870                 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6871                 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6872         }
6873
6874         if (t->materialshaderpass)
6875                 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6876                         R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6877
6878         t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6879         if (t->currentskinframe->qpixels)
6880                 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6881         t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6882         if (!t->basetexture)
6883                 t->basetexture = r_texture_notexture;
6884         t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6885         t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6886         t->nmaptexture = t->currentskinframe->nmap;
6887         if (!t->nmaptexture)
6888                 t->nmaptexture = r_texture_blanknormalmap;
6889         t->glosstexture = r_texture_black;
6890         t->glowtexture = t->currentskinframe->glow;
6891         t->fogtexture = t->currentskinframe->fog;
6892         t->reflectmasktexture = t->currentskinframe->reflect;
6893         if (t->backgroundshaderpass)
6894         {
6895                 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6896                         R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6897                 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6898                 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6899                 t->backgroundglosstexture = r_texture_black;
6900                 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6901                 if (!t->backgroundnmaptexture)
6902                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6903                 // make sure that if glow is going to be used, both textures are not NULL
6904                 if (!t->backgroundglowtexture && t->glowtexture)
6905                         t->backgroundglowtexture = r_texture_black;
6906                 if (!t->glowtexture && t->backgroundglowtexture)
6907                         t->glowtexture = r_texture_black;
6908         }
6909         else
6910         {
6911                 t->backgroundbasetexture = r_texture_white;
6912                 t->backgroundnmaptexture = r_texture_blanknormalmap;
6913                 t->backgroundglosstexture = r_texture_black;
6914                 t->backgroundglowtexture = NULL;
6915         }
6916         t->specularpower = r_shadow_glossexponent.value;
6917         // TODO: store reference values for these in the texture?
6918         if (r_shadow_gloss.integer > 0)
6919         {
6920                 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
6921                 {
6922                         if (r_shadow_glossintensity.value > 0)
6923                         {
6924                                 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
6925                                 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
6926                                 specularscale = r_shadow_glossintensity.value;
6927                         }
6928                 }
6929                 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
6930                 {
6931                         t->glosstexture = r_texture_white;
6932                         t->backgroundglosstexture = r_texture_white;
6933                         specularscale = r_shadow_gloss2intensity.value;
6934                         t->specularpower = r_shadow_gloss2exponent.value;
6935                 }
6936         }
6937         specularscale *= t->specularscalemod;
6938         t->specularpower *= t->specularpowermod;
6939
6940         // lightmaps mode looks bad with dlights using actual texturing, so turn
6941         // off the colormap and glossmap, but leave the normalmap on as it still
6942         // accurately represents the shading involved
6943         if (gl_lightmaps.integer)
6944         {
6945                 t->basetexture = r_texture_grey128;
6946                 t->pantstexture = r_texture_black;
6947                 t->shirttexture = r_texture_black;
6948                 if (gl_lightmaps.integer < 2)
6949                         t->nmaptexture = r_texture_blanknormalmap;
6950                 t->glosstexture = r_texture_black;
6951                 t->glowtexture = NULL;
6952                 t->fogtexture = NULL;
6953                 t->reflectmasktexture = NULL;
6954                 t->backgroundbasetexture = NULL;
6955                 if (gl_lightmaps.integer < 2)
6956                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6957                 t->backgroundglosstexture = r_texture_black;
6958                 t->backgroundglowtexture = NULL;
6959                 specularscale = 0;
6960                 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
6961         }
6962
6963         if (specularscale != 1.0f)
6964         {
6965                 for (q = 0; q < 3; q++)
6966                 {
6967                         t->render_modellight_specular[q] *= specularscale;
6968                         t->render_lightmap_specular[q] *= specularscale;
6969                         t->render_rtlight_specular[q] *= specularscale;
6970                 }
6971         }
6972
6973         t->currentblendfunc[0] = GL_ONE;
6974         t->currentblendfunc[1] = GL_ZERO;
6975         if (t->currentmaterialflags & MATERIALFLAG_ADD)
6976         {
6977                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6978                 t->currentblendfunc[1] = GL_ONE;
6979         }
6980         else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
6981         {
6982                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6983                 t->currentblendfunc[1] = GL_ONE_MINUS_SRC_ALPHA;
6984         }
6985         else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6986         {
6987                 t->currentblendfunc[0] = t->customblendfunc[0];
6988                 t->currentblendfunc[1] = t->customblendfunc[1];
6989         }
6990
6991         return t;
6992 }
6993
6994 rsurfacestate_t rsurface;
6995
6996 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
6997 {
6998         dp_model_t *model = ent->model;
6999         //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
7000         //      return;
7001         rsurface.entity = (entity_render_t *)ent;
7002         rsurface.skeleton = ent->skeleton;
7003         memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
7004         rsurface.ent_skinnum = ent->skinnum;
7005         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;
7006         rsurface.ent_flags = ent->flags;
7007         if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
7008                 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
7009         rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
7010         rsurface.matrix = ent->matrix;
7011         rsurface.inversematrix = ent->inversematrix;
7012         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7013         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7014         R_EntityMatrix(&rsurface.matrix);
7015         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7016         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7017         rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
7018         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7019         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7020         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7021         memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
7022         rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
7023         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7024         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7025         if (ent->model->brush.submodel && !prepass)
7026         {
7027                 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
7028                 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
7029         }
7030         // if the animcache code decided it should use the shader path, skip the deform step
7031         rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
7032         rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
7033         rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
7034         rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
7035         rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
7036         if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
7037         {
7038                 if (ent->animcache_vertex3f)
7039                 {
7040                         r_refdef.stats[r_stat_batch_entitycache_count]++;
7041                         r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
7042                         r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
7043                         r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
7044                         rsurface.modelvertex3f = ent->animcache_vertex3f;
7045                         rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
7046                         rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
7047                         rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
7048                         rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
7049                         rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
7050                         rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
7051                         rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
7052                         rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
7053                         rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
7054                         rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
7055                         rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
7056                 }
7057                 else if (wanttangents)
7058                 {
7059                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7060                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7061                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7062                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7063                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7064                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7065                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7066                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7067                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
7068                         rsurface.modelvertex3f_vertexbuffer = NULL;
7069                         rsurface.modelvertex3f_bufferoffset = 0;
7070                         rsurface.modelvertex3f_vertexbuffer = 0;
7071                         rsurface.modelvertex3f_bufferoffset = 0;
7072                         rsurface.modelsvector3f_vertexbuffer = 0;
7073                         rsurface.modelsvector3f_bufferoffset = 0;
7074                         rsurface.modeltvector3f_vertexbuffer = 0;
7075                         rsurface.modeltvector3f_bufferoffset = 0;
7076                         rsurface.modelnormal3f_vertexbuffer = 0;
7077                         rsurface.modelnormal3f_bufferoffset = 0;
7078                 }
7079                 else if (wantnormals)
7080                 {
7081                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7082                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7083                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7084                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7085                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7086                         rsurface.modelsvector3f = NULL;
7087                         rsurface.modeltvector3f = NULL;
7088                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7089                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
7090                         rsurface.modelvertex3f_vertexbuffer = NULL;
7091                         rsurface.modelvertex3f_bufferoffset = 0;
7092                         rsurface.modelvertex3f_vertexbuffer = 0;
7093                         rsurface.modelvertex3f_bufferoffset = 0;
7094                         rsurface.modelsvector3f_vertexbuffer = 0;
7095                         rsurface.modelsvector3f_bufferoffset = 0;
7096                         rsurface.modeltvector3f_vertexbuffer = 0;
7097                         rsurface.modeltvector3f_bufferoffset = 0;
7098                         rsurface.modelnormal3f_vertexbuffer = 0;
7099                         rsurface.modelnormal3f_bufferoffset = 0;
7100                 }
7101                 else
7102                 {
7103                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7104                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7105                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7106                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7107                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7108                         rsurface.modelsvector3f = NULL;
7109                         rsurface.modeltvector3f = NULL;
7110                         rsurface.modelnormal3f = NULL;
7111                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7112                         rsurface.modelvertex3f_vertexbuffer = NULL;
7113                         rsurface.modelvertex3f_bufferoffset = 0;
7114                         rsurface.modelvertex3f_vertexbuffer = 0;
7115                         rsurface.modelvertex3f_bufferoffset = 0;
7116                         rsurface.modelsvector3f_vertexbuffer = 0;
7117                         rsurface.modelsvector3f_bufferoffset = 0;
7118                         rsurface.modeltvector3f_vertexbuffer = 0;
7119                         rsurface.modeltvector3f_bufferoffset = 0;
7120                         rsurface.modelnormal3f_vertexbuffer = 0;
7121                         rsurface.modelnormal3f_bufferoffset = 0;
7122                 }
7123                 rsurface.modelgeneratedvertex = true;
7124         }
7125         else
7126         {
7127                 if (rsurface.entityskeletaltransform3x4)
7128                 {
7129                         r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7130                         r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7131                         r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7132                         r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7133                 }
7134                 else
7135                 {
7136                         r_refdef.stats[r_stat_batch_entitystatic_count]++;
7137                         r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7138                         r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7139                         r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7140                 }
7141                 rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
7142                 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.data_vertex3f_vertexbuffer;
7143                 rsurface.modelvertex3f_bufferoffset = model->surfmesh.data_vertex3f_bufferoffset;
7144                 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7145                 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.data_svector3f_vertexbuffer;
7146                 rsurface.modelsvector3f_bufferoffset = model->surfmesh.data_svector3f_bufferoffset;
7147                 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7148                 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.data_tvector3f_vertexbuffer;
7149                 rsurface.modeltvector3f_bufferoffset = model->surfmesh.data_tvector3f_bufferoffset;
7150                 rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
7151                 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.data_normal3f_vertexbuffer;
7152                 rsurface.modelnormal3f_bufferoffset = model->surfmesh.data_normal3f_bufferoffset;
7153                 rsurface.modelgeneratedvertex = false;
7154         }
7155         rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
7156         rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.data_lightmapcolor4f_vertexbuffer;
7157         rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.data_lightmapcolor4f_bufferoffset;
7158         rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
7159         rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.data_texcoordtexture2f_vertexbuffer;
7160         rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.data_texcoordtexture2f_bufferoffset;
7161         rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
7162         rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.data_texcoordlightmap2f_vertexbuffer;
7163         rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.data_texcoordlightmap2f_bufferoffset;
7164         rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7165         rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.data_skeletalindex4ub_vertexbuffer;
7166         rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.data_skeletalindex4ub_bufferoffset;
7167         rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7168         rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.data_skeletalweight4ub_vertexbuffer;
7169         rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.data_skeletalweight4ub_bufferoffset;
7170         rsurface.modelelement3i = model->surfmesh.data_element3i;
7171         rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7172         rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7173         rsurface.modelelement3s = model->surfmesh.data_element3s;
7174         rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7175         rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7176         rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7177         rsurface.modelnumvertices = model->surfmesh.num_vertices;
7178         rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7179         rsurface.modelsurfaces = model->data_surfaces;
7180         rsurface.batchgeneratedvertex = false;
7181         rsurface.batchfirstvertex = 0;
7182         rsurface.batchnumvertices = 0;
7183         rsurface.batchfirsttriangle = 0;
7184         rsurface.batchnumtriangles = 0;
7185         rsurface.batchvertex3f  = NULL;
7186         rsurface.batchvertex3f_vertexbuffer = NULL;
7187         rsurface.batchvertex3f_bufferoffset = 0;
7188         rsurface.batchsvector3f = NULL;
7189         rsurface.batchsvector3f_vertexbuffer = NULL;
7190         rsurface.batchsvector3f_bufferoffset = 0;
7191         rsurface.batchtvector3f = NULL;
7192         rsurface.batchtvector3f_vertexbuffer = NULL;
7193         rsurface.batchtvector3f_bufferoffset = 0;
7194         rsurface.batchnormal3f  = NULL;
7195         rsurface.batchnormal3f_vertexbuffer = NULL;
7196         rsurface.batchnormal3f_bufferoffset = 0;
7197         rsurface.batchlightmapcolor4f = NULL;
7198         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7199         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7200         rsurface.batchtexcoordtexture2f = NULL;
7201         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7202         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7203         rsurface.batchtexcoordlightmap2f = NULL;
7204         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7205         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7206         rsurface.batchskeletalindex4ub = NULL;
7207         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7208         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7209         rsurface.batchskeletalweight4ub = NULL;
7210         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7211         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7212         rsurface.batchelement3i = NULL;
7213         rsurface.batchelement3i_indexbuffer = NULL;
7214         rsurface.batchelement3i_bufferoffset = 0;
7215         rsurface.batchelement3s = NULL;
7216         rsurface.batchelement3s_indexbuffer = NULL;
7217         rsurface.batchelement3s_bufferoffset = 0;
7218         rsurface.forcecurrenttextureupdate = false;
7219 }
7220
7221 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)
7222 {
7223         rsurface.entity = r_refdef.scene.worldentity;
7224         if (r != 1.0f || g != 1.0f || b != 1.0f || a != 1.0f) {
7225                 // HACK to provide a valid entity with modded colors to R_GetCurrentTexture.
7226                 // A better approach could be making this copy only once per frame.
7227                 static entity_render_t custom_entity;
7228                 int q;
7229                 custom_entity = *rsurface.entity;
7230                 for (q = 0; q < 3; ++q) {
7231                         float colormod = q == 0 ? r : q == 1 ? g : b;
7232                         custom_entity.render_fullbright[q] *= colormod;
7233                         custom_entity.render_modellight_ambient[q] *= colormod;
7234                         custom_entity.render_modellight_diffuse[q] *= colormod;
7235                         custom_entity.render_lightmap_ambient[q] *= colormod;
7236                         custom_entity.render_lightmap_diffuse[q] *= colormod;
7237                         custom_entity.render_rtlight_diffuse[q] *= colormod;
7238                 }
7239                 custom_entity.alpha *= a;
7240                 rsurface.entity = &custom_entity;
7241         }
7242         rsurface.skeleton = NULL;
7243         rsurface.ent_skinnum = 0;
7244         rsurface.ent_qwskin = -1;
7245         rsurface.ent_flags = entflags;
7246         rsurface.shadertime = r_refdef.scene.time - shadertime;
7247         rsurface.modelnumvertices = numvertices;
7248         rsurface.modelnumtriangles = numtriangles;
7249         rsurface.matrix = *matrix;
7250         rsurface.inversematrix = *inversematrix;
7251         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7252         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7253         R_EntityMatrix(&rsurface.matrix);
7254         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7255         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7256         rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7257         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7258         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7259         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7260         memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7261         rsurface.frameblend[0].lerp = 1;
7262         rsurface.ent_alttextures = false;
7263         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7264         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7265         rsurface.entityskeletaltransform3x4 = NULL;
7266         rsurface.entityskeletaltransform3x4buffer = NULL;
7267         rsurface.entityskeletaltransform3x4offset = 0;
7268         rsurface.entityskeletaltransform3x4size = 0;
7269         rsurface.entityskeletalnumtransforms = 0;
7270         r_refdef.stats[r_stat_batch_entitycustom_count]++;
7271         r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7272         r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7273         r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7274         if (wanttangents)
7275         {
7276                 rsurface.modelvertex3f = (float *)vertex3f;
7277                 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7278                 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7279                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7280         }
7281         else if (wantnormals)
7282         {
7283                 rsurface.modelvertex3f = (float *)vertex3f;
7284                 rsurface.modelsvector3f = NULL;
7285                 rsurface.modeltvector3f = NULL;
7286                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7287         }
7288         else
7289         {
7290                 rsurface.modelvertex3f = (float *)vertex3f;
7291                 rsurface.modelsvector3f = NULL;
7292                 rsurface.modeltvector3f = NULL;
7293                 rsurface.modelnormal3f = NULL;
7294         }
7295         rsurface.modelvertex3f_vertexbuffer = 0;
7296         rsurface.modelvertex3f_bufferoffset = 0;
7297         rsurface.modelsvector3f_vertexbuffer = 0;
7298         rsurface.modelsvector3f_bufferoffset = 0;
7299         rsurface.modeltvector3f_vertexbuffer = 0;
7300         rsurface.modeltvector3f_bufferoffset = 0;
7301         rsurface.modelnormal3f_vertexbuffer = 0;
7302         rsurface.modelnormal3f_bufferoffset = 0;
7303         rsurface.modelgeneratedvertex = true;
7304         rsurface.modellightmapcolor4f  = (float *)color4f;
7305         rsurface.modellightmapcolor4f_vertexbuffer = 0;
7306         rsurface.modellightmapcolor4f_bufferoffset = 0;
7307         rsurface.modeltexcoordtexture2f  = (float *)texcoord2f;
7308         rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7309         rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7310         rsurface.modeltexcoordlightmap2f  = NULL;
7311         rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7312         rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7313         rsurface.modelskeletalindex4ub = NULL;
7314         rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7315         rsurface.modelskeletalindex4ub_bufferoffset = 0;
7316         rsurface.modelskeletalweight4ub = NULL;
7317         rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7318         rsurface.modelskeletalweight4ub_bufferoffset = 0;
7319         rsurface.modelelement3i = (int *)element3i;
7320         rsurface.modelelement3i_indexbuffer = NULL;
7321         rsurface.modelelement3i_bufferoffset = 0;
7322         rsurface.modelelement3s = (unsigned short *)element3s;
7323         rsurface.modelelement3s_indexbuffer = NULL;
7324         rsurface.modelelement3s_bufferoffset = 0;
7325         rsurface.modellightmapoffsets = NULL;
7326         rsurface.modelsurfaces = NULL;
7327         rsurface.batchgeneratedvertex = false;
7328         rsurface.batchfirstvertex = 0;
7329         rsurface.batchnumvertices = 0;
7330         rsurface.batchfirsttriangle = 0;
7331         rsurface.batchnumtriangles = 0;
7332         rsurface.batchvertex3f  = NULL;
7333         rsurface.batchvertex3f_vertexbuffer = NULL;
7334         rsurface.batchvertex3f_bufferoffset = 0;
7335         rsurface.batchsvector3f = NULL;
7336         rsurface.batchsvector3f_vertexbuffer = NULL;
7337         rsurface.batchsvector3f_bufferoffset = 0;
7338         rsurface.batchtvector3f = NULL;
7339         rsurface.batchtvector3f_vertexbuffer = NULL;
7340         rsurface.batchtvector3f_bufferoffset = 0;
7341         rsurface.batchnormal3f  = NULL;
7342         rsurface.batchnormal3f_vertexbuffer = NULL;
7343         rsurface.batchnormal3f_bufferoffset = 0;
7344         rsurface.batchlightmapcolor4f = NULL;
7345         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7346         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7347         rsurface.batchtexcoordtexture2f = NULL;
7348         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7349         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7350         rsurface.batchtexcoordlightmap2f = NULL;
7351         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7352         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7353         rsurface.batchskeletalindex4ub = NULL;
7354         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7355         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7356         rsurface.batchskeletalweight4ub = NULL;
7357         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7358         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7359         rsurface.batchelement3i = NULL;
7360         rsurface.batchelement3i_indexbuffer = NULL;
7361         rsurface.batchelement3i_bufferoffset = 0;
7362         rsurface.batchelement3s = NULL;
7363         rsurface.batchelement3s_indexbuffer = NULL;
7364         rsurface.batchelement3s_bufferoffset = 0;
7365         rsurface.forcecurrenttextureupdate = true;
7366
7367         if (rsurface.modelnumvertices && rsurface.modelelement3i)
7368         {
7369                 if ((wantnormals || wanttangents) && !normal3f)
7370                 {
7371                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7372                         Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7373                 }
7374                 if (wanttangents && !svector3f)
7375                 {
7376                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7377                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7378                         Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7379                 }
7380         }
7381 }
7382
7383 float RSurf_FogPoint(const float *v)
7384 {
7385         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7386         float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7387         float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7388         float FogHeightFade = r_refdef.fogheightfade;
7389         float fogfrac;
7390         unsigned int fogmasktableindex;
7391         if (r_refdef.fogplaneviewabove)
7392                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7393         else
7394                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7395         fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7396         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7397 }
7398
7399 float RSurf_FogVertex(const float *v)
7400 {
7401         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7402         float FogPlaneViewDist = rsurface.fogplaneviewdist;
7403         float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7404         float FogHeightFade = rsurface.fogheightfade;
7405         float fogfrac;
7406         unsigned int fogmasktableindex;
7407         if (r_refdef.fogplaneviewabove)
7408                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7409         else
7410                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7411         fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7412         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7413 }
7414
7415 void RSurf_UploadBuffersForBatch(void)
7416 {
7417         // upload buffer data for generated vertex data (dynamicvertex case) or index data (copytriangles case) and models that lack it to begin with (e.g. DrawQ_FlushUI)
7418         // note that if rsurface.batchvertex3f_vertexbuffer is NULL, dynamicvertex is forced as we don't account for the proper base vertex here.
7419         if (rsurface.batchvertex3f && !rsurface.batchvertex3f_vertexbuffer)
7420                 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
7421         if (rsurface.batchsvector3f && !rsurface.batchsvector3f_vertexbuffer)
7422                 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
7423         if (rsurface.batchtvector3f && !rsurface.batchtvector3f_vertexbuffer)
7424                 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
7425         if (rsurface.batchnormal3f && !rsurface.batchnormal3f_vertexbuffer)
7426                 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
7427         if (rsurface.batchlightmapcolor4f && !rsurface.batchlightmapcolor4f_vertexbuffer)
7428                 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
7429         if (rsurface.batchtexcoordtexture2f && !rsurface.batchtexcoordtexture2f_vertexbuffer)
7430                 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
7431         if (rsurface.batchtexcoordlightmap2f && !rsurface.batchtexcoordlightmap2f_vertexbuffer)
7432                 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
7433         if (rsurface.batchskeletalindex4ub && !rsurface.batchskeletalindex4ub_vertexbuffer)
7434                 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
7435         if (rsurface.batchskeletalweight4ub && !rsurface.batchskeletalweight4ub_vertexbuffer)
7436                 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
7437
7438         if (rsurface.batchelement3s && !rsurface.batchelement3s_indexbuffer)
7439                 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
7440         else if (rsurface.batchelement3i && !rsurface.batchelement3i_indexbuffer)
7441                 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
7442
7443         R_Mesh_VertexPointer(     3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
7444         R_Mesh_ColorPointer(      4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
7445         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
7446         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
7447         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
7448         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
7449         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
7450         R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
7451         R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
7452         R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
7453 }
7454
7455 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7456 {
7457         int i;
7458         for (i = 0;i < numelements;i++)
7459                 outelement3i[i] = inelement3i[i] + adjust;
7460 }
7461
7462 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7463 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7464 {
7465         int deformindex;
7466         int firsttriangle;
7467         int numtriangles;
7468         int firstvertex;
7469         int endvertex;
7470         int numvertices;
7471         int surfacefirsttriangle;
7472         int surfacenumtriangles;
7473         int surfacefirstvertex;
7474         int surfaceendvertex;
7475         int surfacenumvertices;
7476         int batchnumsurfaces = texturenumsurfaces;
7477         int batchnumvertices;
7478         int batchnumtriangles;
7479         int i, j;
7480         qboolean gaps;
7481         qboolean dynamicvertex;
7482         float amplitude;
7483         float animpos;
7484         float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7485         float waveparms[4];
7486         unsigned char *ub;
7487         q3shaderinfo_deform_t *deform;
7488         const msurface_t *surface, *firstsurface;
7489         if (!texturenumsurfaces)
7490                 return;
7491         // find vertex range of this surface batch
7492         gaps = false;
7493         firstsurface = texturesurfacelist[0];
7494         firsttriangle = firstsurface->num_firsttriangle;
7495         batchnumvertices = 0;
7496         batchnumtriangles = 0;
7497         firstvertex = endvertex = firstsurface->num_firstvertex;
7498         for (i = 0;i < texturenumsurfaces;i++)
7499         {
7500                 surface = texturesurfacelist[i];
7501                 if (surface != firstsurface + i)
7502                         gaps = true;
7503                 surfacefirstvertex = surface->num_firstvertex;
7504                 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7505                 surfacenumvertices = surface->num_vertices;
7506                 surfacenumtriangles = surface->num_triangles;
7507                 if (firstvertex > surfacefirstvertex)
7508                         firstvertex = surfacefirstvertex;
7509                 if (endvertex < surfaceendvertex)
7510                         endvertex = surfaceendvertex;
7511                 batchnumvertices += surfacenumvertices;
7512                 batchnumtriangles += surfacenumtriangles;
7513         }
7514
7515         r_refdef.stats[r_stat_batch_batches]++;
7516         if (gaps)
7517                 r_refdef.stats[r_stat_batch_withgaps]++;
7518         r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7519         r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7520         r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7521
7522         // we now know the vertex range used, and if there are any gaps in it
7523         rsurface.batchfirstvertex = firstvertex;
7524         rsurface.batchnumvertices = endvertex - firstvertex;
7525         rsurface.batchfirsttriangle = firsttriangle;
7526         rsurface.batchnumtriangles = batchnumtriangles;
7527
7528         // check if any dynamic vertex processing must occur
7529         dynamicvertex = false;
7530
7531         // we must use vertexbuffers for rendering, we can upload vertex buffers
7532         // easily enough but if the basevertex is non-zero it becomes more
7533         // difficult, so force dynamicvertex path in that case - it's suboptimal
7534         // but the most optimal case is to have the geometry sources provide their
7535         // own anyway.
7536         if (!rsurface.modelvertex3f_vertexbuffer && firstvertex != 0)
7537                 dynamicvertex = true;
7538
7539         // a cvar to force the dynamic vertex path to be taken, for debugging
7540         if (r_batch_debugdynamicvertexpath.integer)
7541         {
7542                 if (!dynamicvertex)
7543                 {
7544                         r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7545                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7546                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7547                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7548                 }
7549                 dynamicvertex = true;
7550         }
7551
7552         // if there is a chance of animated vertex colors, it's a dynamic batch
7553         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
7554         {
7555                 if (!dynamicvertex)
7556                 {
7557                         r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7558                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7559                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7560                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7561                 }
7562                 dynamicvertex = true;
7563         }
7564
7565         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7566         {
7567                 switch (deform->deform)
7568                 {
7569                 default:
7570                 case Q3DEFORM_PROJECTIONSHADOW:
7571                 case Q3DEFORM_TEXT0:
7572                 case Q3DEFORM_TEXT1:
7573                 case Q3DEFORM_TEXT2:
7574                 case Q3DEFORM_TEXT3:
7575                 case Q3DEFORM_TEXT4:
7576                 case Q3DEFORM_TEXT5:
7577                 case Q3DEFORM_TEXT6:
7578                 case Q3DEFORM_TEXT7:
7579                 case Q3DEFORM_NONE:
7580                         break;
7581                 case Q3DEFORM_AUTOSPRITE:
7582                         if (!dynamicvertex)
7583                         {
7584                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7585                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7586                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7587                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7588                         }
7589                         dynamicvertex = true;
7590                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7591                         break;
7592                 case Q3DEFORM_AUTOSPRITE2:
7593                         if (!dynamicvertex)
7594                         {
7595                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7596                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7597                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7598                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7599                         }
7600                         dynamicvertex = true;
7601                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7602                         break;
7603                 case Q3DEFORM_NORMAL:
7604                         if (!dynamicvertex)
7605                         {
7606                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7607                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7608                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7609                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7610                         }
7611                         dynamicvertex = true;
7612                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7613                         break;
7614                 case Q3DEFORM_WAVE:
7615                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7616                                 break; // if wavefunc is a nop, ignore this transform
7617                         if (!dynamicvertex)
7618                         {
7619                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7620                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7621                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7622                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7623                         }
7624                         dynamicvertex = true;
7625                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7626                         break;
7627                 case Q3DEFORM_BULGE:
7628                         if (!dynamicvertex)
7629                         {
7630                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7631                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7632                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7633                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7634                         }
7635                         dynamicvertex = true;
7636                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7637                         break;
7638                 case Q3DEFORM_MOVE:
7639                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7640                                 break; // if wavefunc is a nop, ignore this transform
7641                         if (!dynamicvertex)
7642                         {
7643                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7644                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7645                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7646                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7647                         }
7648                         dynamicvertex = true;
7649                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7650                         break;
7651                 }
7652         }
7653         if (rsurface.texture->materialshaderpass)
7654         {
7655                 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7656                 {
7657                 default:
7658                 case Q3TCGEN_TEXTURE:
7659                         break;
7660                 case Q3TCGEN_LIGHTMAP:
7661                         if (!dynamicvertex)
7662                         {
7663                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7664                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7665                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7666                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7667                         }
7668                         dynamicvertex = true;
7669                         batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7670                         break;
7671                 case Q3TCGEN_VECTOR:
7672                         if (!dynamicvertex)
7673                         {
7674                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7675                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7676                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7677                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7678                         }
7679                         dynamicvertex = true;
7680                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7681                         break;
7682                 case Q3TCGEN_ENVIRONMENT:
7683                         if (!dynamicvertex)
7684                         {
7685                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7686                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7687                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7688                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7689                         }
7690                         dynamicvertex = true;
7691                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7692                         break;
7693                 }
7694                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7695                 {
7696                         if (!dynamicvertex)
7697                         {
7698                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7699                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7700                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7701                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7702                         }
7703                         dynamicvertex = true;
7704                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7705                 }
7706         }
7707
7708         // the caller can specify BATCHNEED_NOGAPS to force a batch with
7709         // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7710         // we ensure this by treating the vertex batch as dynamic...
7711         if ((batchneed & BATCHNEED_ALWAYSCOPY) || ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0)))
7712         {
7713                 if (!dynamicvertex)
7714                 {
7715                         r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7716                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7717                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7718                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7719                 }
7720                 dynamicvertex = true;
7721         }
7722
7723         // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7724         if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7725                 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7726
7727         rsurface.batchvertex3f = rsurface.modelvertex3f;
7728         rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7729         rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7730         rsurface.batchsvector3f = rsurface.modelsvector3f;
7731         rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7732         rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7733         rsurface.batchtvector3f = rsurface.modeltvector3f;
7734         rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7735         rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7736         rsurface.batchnormal3f = rsurface.modelnormal3f;
7737         rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7738         rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7739         rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7740         rsurface.batchlightmapcolor4f_vertexbuffer  = rsurface.modellightmapcolor4f_vertexbuffer;
7741         rsurface.batchlightmapcolor4f_bufferoffset  = rsurface.modellightmapcolor4f_bufferoffset;
7742         rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7743         rsurface.batchtexcoordtexture2f_vertexbuffer  = rsurface.modeltexcoordtexture2f_vertexbuffer;
7744         rsurface.batchtexcoordtexture2f_bufferoffset  = rsurface.modeltexcoordtexture2f_bufferoffset;
7745         rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7746         rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7747         rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7748         rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7749         rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7750         rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7751         rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7752         rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7753         rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7754         rsurface.batchelement3i = rsurface.modelelement3i;
7755         rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7756         rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7757         rsurface.batchelement3s = rsurface.modelelement3s;
7758         rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7759         rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7760         rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7761         rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7762         rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7763         rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7764         rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7765
7766         // if any dynamic vertex processing has to occur in software, we copy the
7767         // entire surface list together before processing to rebase the vertices
7768         // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7769         //
7770         // if any gaps exist and we do not have a static vertex buffer, we have to
7771         // copy the surface list together to avoid wasting upload bandwidth on the
7772         // vertices in the gaps.
7773         //
7774         // if gaps exist and we have a static vertex buffer, we can choose whether
7775         // to combine the index buffer ranges into one dynamic index buffer or
7776         // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7777         //
7778         // in many cases the batch is reduced to one draw call.
7779
7780         rsurface.batchmultidraw = false;
7781         rsurface.batchmultidrawnumsurfaces = 0;
7782         rsurface.batchmultidrawsurfacelist = NULL;
7783
7784         if (!dynamicvertex)
7785         {
7786                 // static vertex data, just set pointers...
7787                 rsurface.batchgeneratedvertex = false;
7788                 // if there are gaps, we want to build a combined index buffer,
7789                 // otherwise use the original static buffer with an appropriate offset
7790                 if (gaps)
7791                 {
7792                         r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7793                         r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7794                         r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7795                         r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7796                         if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7797                         {
7798                                 rsurface.batchmultidraw = true;
7799                                 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7800                                 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7801                                 return;
7802                         }
7803                         // build a new triangle elements array for this batch
7804                         rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7805                         rsurface.batchfirsttriangle = 0;
7806                         numtriangles = 0;
7807                         for (i = 0;i < texturenumsurfaces;i++)
7808                         {
7809                                 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7810                                 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7811                                 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7812                                 numtriangles += surfacenumtriangles;
7813                         }
7814                         rsurface.batchelement3i_indexbuffer = NULL;
7815                         rsurface.batchelement3i_bufferoffset = 0;
7816                         rsurface.batchelement3s = NULL;
7817                         rsurface.batchelement3s_indexbuffer = NULL;
7818                         rsurface.batchelement3s_bufferoffset = 0;
7819                         if (endvertex <= 65536)
7820                         {
7821                                 // make a 16bit (unsigned short) index array if possible
7822                                 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7823                                 for (i = 0;i < numtriangles*3;i++)
7824                                         rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7825                         }
7826                 }
7827                 else
7828                 {
7829                         r_refdef.stats[r_stat_batch_fast_batches] += 1;
7830                         r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
7831                         r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
7832                         r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
7833                 }
7834                 return;
7835         }
7836
7837         // something needs software processing, do it for real...
7838         // we only directly handle separate array data in this case and then
7839         // generate interleaved data if needed...
7840         rsurface.batchgeneratedvertex = true;
7841         r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
7842         r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
7843         r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
7844         r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
7845
7846         // now copy the vertex data into a combined array and make an index array
7847         // (this is what Quake3 does all the time)
7848         // we also apply any skeletal animation here that would have been done in
7849         // the vertex shader, because most of the dynamic vertex animation cases
7850         // need actual vertex positions and normals
7851         //if (dynamicvertex)
7852         {
7853                 rsurface.batchvertex3f = NULL;
7854                 rsurface.batchvertex3f_vertexbuffer = NULL;
7855                 rsurface.batchvertex3f_bufferoffset = 0;
7856                 rsurface.batchsvector3f = NULL;
7857                 rsurface.batchsvector3f_vertexbuffer = NULL;
7858                 rsurface.batchsvector3f_bufferoffset = 0;
7859                 rsurface.batchtvector3f = NULL;
7860                 rsurface.batchtvector3f_vertexbuffer = NULL;
7861                 rsurface.batchtvector3f_bufferoffset = 0;
7862                 rsurface.batchnormal3f = NULL;
7863                 rsurface.batchnormal3f_vertexbuffer = NULL;
7864                 rsurface.batchnormal3f_bufferoffset = 0;
7865                 rsurface.batchlightmapcolor4f = NULL;
7866                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7867                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7868                 rsurface.batchtexcoordtexture2f = NULL;
7869                 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7870                 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7871                 rsurface.batchtexcoordlightmap2f = NULL;
7872                 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7873                 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7874                 rsurface.batchskeletalindex4ub = NULL;
7875                 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7876                 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7877                 rsurface.batchskeletalweight4ub = NULL;
7878                 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7879                 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7880                 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7881                 rsurface.batchelement3i_indexbuffer = NULL;
7882                 rsurface.batchelement3i_bufferoffset = 0;
7883                 rsurface.batchelement3s = NULL;
7884                 rsurface.batchelement3s_indexbuffer = NULL;
7885                 rsurface.batchelement3s_bufferoffset = 0;
7886                 rsurface.batchskeletaltransform3x4buffer = NULL;
7887                 rsurface.batchskeletaltransform3x4offset = 0;
7888                 rsurface.batchskeletaltransform3x4size = 0;
7889                 // we'll only be setting up certain arrays as needed
7890                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7891                         rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7892                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7893                         rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7894                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7895                 {
7896                         rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7897                         rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7898                 }
7899                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7900                         rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
7901                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7902                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7903                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7904                         rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7905                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7906                 {
7907                         rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7908                         rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7909                 }
7910                 numvertices = 0;
7911                 numtriangles = 0;
7912                 for (i = 0;i < texturenumsurfaces;i++)
7913                 {
7914                         surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
7915                         surfacenumvertices = texturesurfacelist[i]->num_vertices;
7916                         surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7917                         surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7918                         // copy only the data requested
7919                         if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
7920                         {
7921                                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7922                                 {
7923                                         if (rsurface.batchvertex3f)
7924                                                 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7925                                         else
7926                                                 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7927                                 }
7928                                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7929                                 {
7930                                         if (rsurface.modelnormal3f)
7931                                                 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7932                                         else
7933                                                 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7934                                 }
7935                                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7936                                 {
7937                                         if (rsurface.modelsvector3f)
7938                                         {
7939                                                 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7940                                                 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7941                                         }
7942                                         else
7943                                         {
7944                                                 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7945                                                 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7946                                         }
7947                                 }
7948                                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7949                                 {
7950                                         if (rsurface.modellightmapcolor4f)
7951                                                 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
7952                                         else
7953                                                 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
7954                                 }
7955                                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7956                                 {
7957                                         if (rsurface.modeltexcoordtexture2f)
7958                                                 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7959                                         else
7960                                                 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7961                                 }
7962                                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7963                                 {
7964                                         if (rsurface.modeltexcoordlightmap2f)
7965                                                 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7966                                         else
7967                                                 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7968                                 }
7969                                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7970                                 {
7971                                         if (rsurface.modelskeletalindex4ub)
7972                                         {
7973                                                 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7974                                                 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7975                                         }
7976                                         else
7977                                         {
7978                                                 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7979                                                 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7980                                                 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
7981                                                 for (j = 0;j < surfacenumvertices;j++)
7982                                                         ub[j*4] = 255;
7983                                         }
7984                                 }
7985                         }
7986                         RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
7987                         numvertices += surfacenumvertices;
7988                         numtriangles += surfacenumtriangles;
7989                 }
7990
7991                 // generate a 16bit index array as well if possible
7992                 // (in general, dynamic batches fit)
7993                 if (numvertices <= 65536)
7994                 {
7995                         rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7996                         for (i = 0;i < numtriangles*3;i++)
7997                                 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7998                 }
7999
8000                 // since we've copied everything, the batch now starts at 0
8001                 rsurface.batchfirstvertex = 0;
8002                 rsurface.batchnumvertices = batchnumvertices;
8003                 rsurface.batchfirsttriangle = 0;
8004                 rsurface.batchnumtriangles = batchnumtriangles;
8005         }
8006
8007         // apply skeletal animation that would have been done in the vertex shader
8008         if (rsurface.batchskeletaltransform3x4)
8009         {
8010                 const unsigned char *si;
8011                 const unsigned char *sw;
8012                 const float *t[4];
8013                 const float *b = rsurface.batchskeletaltransform3x4;
8014                 float *vp, *vs, *vt, *vn;
8015                 float w[4];
8016                 float m[3][4], n[3][4];
8017                 float tp[3], ts[3], tt[3], tn[3];
8018                 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
8019                 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
8020                 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
8021                 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
8022                 si = rsurface.batchskeletalindex4ub;
8023                 sw = rsurface.batchskeletalweight4ub;
8024                 vp = rsurface.batchvertex3f;
8025                 vs = rsurface.batchsvector3f;
8026                 vt = rsurface.batchtvector3f;
8027                 vn = rsurface.batchnormal3f;
8028                 memset(m[0], 0, sizeof(m));
8029                 memset(n[0], 0, sizeof(n));
8030                 for (i = 0;i < batchnumvertices;i++)
8031                 {
8032                         t[0] = b + si[0]*12;
8033                         if (sw[0] == 255)
8034                         {
8035                                 // common case - only one matrix
8036                                 m[0][0] = t[0][ 0];
8037                                 m[0][1] = t[0][ 1];
8038                                 m[0][2] = t[0][ 2];
8039                                 m[0][3] = t[0][ 3];
8040                                 m[1][0] = t[0][ 4];
8041                                 m[1][1] = t[0][ 5];
8042                                 m[1][2] = t[0][ 6];
8043                                 m[1][3] = t[0][ 7];
8044                                 m[2][0] = t[0][ 8];
8045                                 m[2][1] = t[0][ 9];
8046                                 m[2][2] = t[0][10];
8047                                 m[2][3] = t[0][11];
8048                         }
8049                         else if (sw[2] + sw[3])
8050                         {
8051                                 // blend 4 matrices
8052                                 t[1] = b + si[1]*12;
8053                                 t[2] = b + si[2]*12;
8054                                 t[3] = b + si[3]*12;
8055                                 w[0] = sw[0] * (1.0f / 255.0f);
8056                                 w[1] = sw[1] * (1.0f / 255.0f);
8057                                 w[2] = sw[2] * (1.0f / 255.0f);
8058                                 w[3] = sw[3] * (1.0f / 255.0f);
8059                                 // blend the matrices
8060                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
8061                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
8062                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
8063                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
8064                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
8065                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
8066                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
8067                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
8068                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
8069                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
8070                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
8071                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
8072                         }
8073                         else
8074                         {
8075                                 // blend 2 matrices
8076                                 t[1] = b + si[1]*12;
8077                                 w[0] = sw[0] * (1.0f / 255.0f);
8078                                 w[1] = sw[1] * (1.0f / 255.0f);
8079                                 // blend the matrices
8080                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
8081                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
8082                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
8083                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
8084                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
8085                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
8086                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
8087                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
8088                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
8089                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
8090                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
8091                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
8092                         }
8093                         si += 4;
8094                         sw += 4;
8095                         // modify the vertex
8096                         VectorCopy(vp, tp);
8097                         vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
8098                         vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
8099                         vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
8100                         vp += 3;
8101                         if (vn)
8102                         {
8103                                 // the normal transformation matrix is a set of cross products...
8104                                 CrossProduct(m[1], m[2], n[0]);
8105                                 CrossProduct(m[2], m[0], n[1]);
8106                                 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8107                                 VectorCopy(vn, tn);
8108                                 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8109                                 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8110                                 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8111                                 VectorNormalize(vn);
8112                                 vn += 3;
8113                                 if (vs)
8114                                 {
8115                                         VectorCopy(vs, ts);
8116                                         vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8117                                         vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8118                                         vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8119                                         VectorNormalize(vs);
8120                                         vs += 3;
8121                                         VectorCopy(vt, tt);
8122                                         vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8123                                         vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8124                                         vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8125                                         VectorNormalize(vt);
8126                                         vt += 3;
8127                                 }
8128                         }
8129                 }
8130                 rsurface.batchskeletaltransform3x4 = NULL;
8131                 rsurface.batchskeletalnumtransforms = 0;
8132         }
8133
8134         // q1bsp surfaces rendered in vertex color mode have to have colors
8135         // calculated based on lightstyles
8136         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
8137         {
8138                 // generate color arrays for the surfaces in this list
8139                 int c[4];
8140                 int scale;
8141                 int size3;
8142                 const int *offsets;
8143                 const unsigned char *lm;
8144                 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8145                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8146                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8147                 numvertices = 0;
8148                 for (i = 0;i < texturenumsurfaces;i++)
8149                 {
8150                         surface = texturesurfacelist[i];
8151                         offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8152                         surfacenumvertices = surface->num_vertices;
8153                         if (surface->lightmapinfo->samples)
8154                         {
8155                                 for (j = 0;j < surfacenumvertices;j++)
8156                                 {
8157                                         lm = surface->lightmapinfo->samples + offsets[j];
8158                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8159                                         VectorScale(lm, scale, c);
8160                                         if (surface->lightmapinfo->styles[1] != 255)
8161                                         {
8162                                                 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8163                                                 lm += size3;
8164                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8165                                                 VectorMA(c, scale, lm, c);
8166                                                 if (surface->lightmapinfo->styles[2] != 255)
8167                                                 {
8168                                                         lm += size3;
8169                                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8170                                                         VectorMA(c, scale, lm, c);
8171                                                         if (surface->lightmapinfo->styles[3] != 255)
8172                                                         {
8173                                                                 lm += size3;
8174                                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8175                                                                 VectorMA(c, scale, lm, c);
8176                                                         }
8177                                                 }
8178                                         }
8179                                         c[0] >>= 7;
8180                                         c[1] >>= 7;
8181                                         c[2] >>= 7;
8182                                         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);
8183                                         numvertices++;
8184                                 }
8185                         }
8186                         else
8187                         {
8188                                 for (j = 0;j < surfacenumvertices;j++)
8189                                 {
8190                                         Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8191                                         numvertices++;
8192                                 }
8193                         }
8194                 }
8195         }
8196
8197         // if vertices are deformed (sprite flares and things in maps, possibly
8198         // water waves, bulges and other deformations), modify the copied vertices
8199         // in place
8200         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8201         {
8202                 float scale;
8203                 switch (deform->deform)
8204                 {
8205                 default:
8206                 case Q3DEFORM_PROJECTIONSHADOW:
8207                 case Q3DEFORM_TEXT0:
8208                 case Q3DEFORM_TEXT1:
8209                 case Q3DEFORM_TEXT2:
8210                 case Q3DEFORM_TEXT3:
8211                 case Q3DEFORM_TEXT4:
8212                 case Q3DEFORM_TEXT5:
8213                 case Q3DEFORM_TEXT6:
8214                 case Q3DEFORM_TEXT7:
8215                 case Q3DEFORM_NONE:
8216                         break;
8217                 case Q3DEFORM_AUTOSPRITE:
8218                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8219                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8220                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8221                         VectorNormalize(newforward);
8222                         VectorNormalize(newright);
8223                         VectorNormalize(newup);
8224 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8225 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8226 //                      rsurface.batchvertex3f_bufferoffset = 0;
8227 //                      rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8228 //                      rsurface.batchsvector3f_vertexbuffer = NULL;
8229 //                      rsurface.batchsvector3f_bufferoffset = 0;
8230 //                      rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8231 //                      rsurface.batchtvector3f_vertexbuffer = NULL;
8232 //                      rsurface.batchtvector3f_bufferoffset = 0;
8233 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8234 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8235 //                      rsurface.batchnormal3f_bufferoffset = 0;
8236                         // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8237                         if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8238                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8239                         if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8240                                 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);
8241                         // a single autosprite surface can contain multiple sprites...
8242                         for (j = 0;j < batchnumvertices - 3;j += 4)
8243                         {
8244                                 VectorClear(center);
8245                                 for (i = 0;i < 4;i++)
8246                                         VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8247                                 VectorScale(center, 0.25f, center);
8248                                 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8249                                 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8250                                 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8251                                 for (i = 0;i < 4;i++)
8252                                 {
8253                                         VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8254                                         VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8255                                 }
8256                         }
8257                         // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8258                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8259                         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);
8260                         break;
8261                 case Q3DEFORM_AUTOSPRITE2:
8262                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8263                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8264                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8265                         VectorNormalize(newforward);
8266                         VectorNormalize(newright);
8267                         VectorNormalize(newup);
8268 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8269 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8270 //                      rsurface.batchvertex3f_bufferoffset = 0;
8271                         {
8272                                 const float *v1, *v2;
8273                                 vec3_t start, end;
8274                                 float f, l;
8275                                 struct
8276                                 {
8277                                         float length2;
8278                                         const float *v1;
8279                                         const float *v2;
8280                                 }
8281                                 shortest[2];
8282                                 memset(shortest, 0, sizeof(shortest));
8283                                 // a single autosprite surface can contain multiple sprites...
8284                                 for (j = 0;j < batchnumvertices - 3;j += 4)
8285                                 {
8286                                         VectorClear(center);
8287                                         for (i = 0;i < 4;i++)
8288                                                 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8289                                         VectorScale(center, 0.25f, center);
8290                                         // find the two shortest edges, then use them to define the
8291                                         // axis vectors for rotating around the central axis
8292                                         for (i = 0;i < 6;i++)
8293                                         {
8294                                                 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8295                                                 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8296                                                 l = VectorDistance2(v1, v2);
8297                                                 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8298                                                 if (v1[2] != v2[2])
8299                                                         l += (1.0f / 1024.0f);
8300                                                 if (shortest[0].length2 > l || i == 0)
8301                                                 {
8302                                                         shortest[1] = shortest[0];
8303                                                         shortest[0].length2 = l;
8304                                                         shortest[0].v1 = v1;
8305                                                         shortest[0].v2 = v2;
8306                                                 }
8307                                                 else if (shortest[1].length2 > l || i == 1)
8308                                                 {
8309                                                         shortest[1].length2 = l;
8310                                                         shortest[1].v1 = v1;
8311                                                         shortest[1].v2 = v2;
8312                                                 }
8313                                         }
8314                                         VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8315                                         VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8316                                         // this calculates the right vector from the shortest edge
8317                                         // and the up vector from the edge midpoints
8318                                         VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8319                                         VectorNormalize(right);
8320                                         VectorSubtract(end, start, up);
8321                                         VectorNormalize(up);
8322                                         // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8323                                         VectorSubtract(rsurface.localvieworigin, center, forward);
8324                                         //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8325                                         VectorNegate(forward, forward);
8326                                         VectorReflect(forward, 0, up, forward);
8327                                         VectorNormalize(forward);
8328                                         CrossProduct(up, forward, newright);
8329                                         VectorNormalize(newright);
8330                                         // rotate the quad around the up axis vector, this is made
8331                                         // especially easy by the fact we know the quad is flat,
8332                                         // so we only have to subtract the center position and
8333                                         // measure distance along the right vector, and then
8334                                         // multiply that by the newright vector and add back the
8335                                         // center position
8336                                         // we also need to subtract the old position to undo the
8337                                         // displacement from the center, which we do with a
8338                                         // DotProduct, the subtraction/addition of center is also
8339                                         // optimized into DotProducts here
8340                                         l = DotProduct(right, center);
8341                                         for (i = 0;i < 4;i++)
8342                                         {
8343                                                 v1 = rsurface.batchvertex3f + 3*(j+i);
8344                                                 f = DotProduct(right, v1) - l;
8345                                                 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8346                                         }
8347                                 }
8348                         }
8349                         if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8350                         {
8351 //                              rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8352 //                              rsurface.batchnormal3f_vertexbuffer = NULL;
8353 //                              rsurface.batchnormal3f_bufferoffset = 0;
8354                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8355                         }
8356                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8357                         {
8358 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8359 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8360 //                              rsurface.batchsvector3f_bufferoffset = 0;
8361 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8362 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8363 //                              rsurface.batchtvector3f_bufferoffset = 0;
8364                                 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);
8365                         }
8366                         break;
8367                 case Q3DEFORM_NORMAL:
8368                         // deform the normals to make reflections wavey
8369                         rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8370                         rsurface.batchnormal3f_vertexbuffer = NULL;
8371                         rsurface.batchnormal3f_bufferoffset = 0;
8372                         for (j = 0;j < batchnumvertices;j++)
8373                         {
8374                                 float vertex[3];
8375                                 float *normal = rsurface.batchnormal3f + 3*j;
8376                                 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8377                                 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8378                                 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8379                                 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8380                                 VectorNormalize(normal);
8381                         }
8382                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8383                         {
8384 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8385 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8386 //                              rsurface.batchsvector3f_bufferoffset = 0;
8387 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8388 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8389 //                              rsurface.batchtvector3f_bufferoffset = 0;
8390                                 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);
8391                         }
8392                         break;
8393                 case Q3DEFORM_WAVE:
8394                         // deform vertex array to make wavey water and flags and such
8395                         waveparms[0] = deform->waveparms[0];
8396                         waveparms[1] = deform->waveparms[1];
8397                         waveparms[2] = deform->waveparms[2];
8398                         waveparms[3] = deform->waveparms[3];
8399                         if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8400                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8401                         // this is how a divisor of vertex influence on deformation
8402                         animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8403                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8404 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8405 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8406 //                      rsurface.batchvertex3f_bufferoffset = 0;
8407 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8408 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8409 //                      rsurface.batchnormal3f_bufferoffset = 0;
8410                         for (j = 0;j < batchnumvertices;j++)
8411                         {
8412                                 // if the wavefunc depends on time, evaluate it per-vertex
8413                                 if (waveparms[3])
8414                                 {
8415                                         waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8416                                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8417                                 }
8418                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8419                         }
8420                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8421                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8422                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8423                         {
8424 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8425 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8426 //                              rsurface.batchsvector3f_bufferoffset = 0;
8427 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8428 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8429 //                              rsurface.batchtvector3f_bufferoffset = 0;
8430                                 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);
8431                         }
8432                         break;
8433                 case Q3DEFORM_BULGE:
8434                         // deform vertex array to make the surface have moving bulges
8435 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8436 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8437 //                      rsurface.batchvertex3f_bufferoffset = 0;
8438 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8439 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8440 //                      rsurface.batchnormal3f_bufferoffset = 0;
8441                         for (j = 0;j < batchnumvertices;j++)
8442                         {
8443                                 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8444                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8445                         }
8446                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8447                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8448                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8449                         {
8450 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8451 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8452 //                              rsurface.batchsvector3f_bufferoffset = 0;
8453 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8454 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8455 //                              rsurface.batchtvector3f_bufferoffset = 0;
8456                                 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);
8457                         }
8458                         break;
8459                 case Q3DEFORM_MOVE:
8460                         // deform vertex array
8461                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8462                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8463                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8464                         VectorScale(deform->parms, scale, waveparms);
8465 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8466 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8467 //                      rsurface.batchvertex3f_bufferoffset = 0;
8468                         for (j = 0;j < batchnumvertices;j++)
8469                                 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8470                         break;
8471                 }
8472         }
8473
8474         if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8475         {
8476         // generate texcoords based on the chosen texcoord source
8477                 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8478                 {
8479                 default:
8480                 case Q3TCGEN_TEXTURE:
8481                         break;
8482                 case Q3TCGEN_LIGHTMAP:
8483         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8484         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8485         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8486                         if (rsurface.batchtexcoordlightmap2f)
8487                                 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8488                         break;
8489                 case Q3TCGEN_VECTOR:
8490         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8491         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8492         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8493                         for (j = 0;j < batchnumvertices;j++)
8494                         {
8495                                 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8496                                 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8497                         }
8498                         break;
8499                 case Q3TCGEN_ENVIRONMENT:
8500                         // make environment reflections using a spheremap
8501                         rsurface.batchtexcoordtexture2f = (float *)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                                 // identical to Q3A's method, but executed in worldspace so
8507                                 // carried models can be shiny too
8508
8509                                 float viewer[3], d, reflected[3], worldreflected[3];
8510
8511                                 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8512                                 // VectorNormalize(viewer);
8513
8514                                 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8515
8516                                 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8517                                 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8518                                 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8519                                 // note: this is proportinal to viewer, so we can normalize later
8520
8521                                 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8522                                 VectorNormalize(worldreflected);
8523
8524                                 // note: this sphere map only uses world x and z!
8525                                 // so positive and negative y will LOOK THE SAME.
8526                                 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8527                                 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8528                         }
8529                         break;
8530                 }
8531                 // the only tcmod that needs software vertex processing is turbulent, so
8532                 // check for it here and apply the changes if needed
8533                 // and we only support that as the first one
8534                 // (handling a mixture of turbulent and other tcmods would be problematic
8535                 //  without punting it entirely to a software path)
8536                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8537                 {
8538                         amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8539                         animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8540         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8541         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8542         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8543                         for (j = 0;j < batchnumvertices;j++)
8544                         {
8545                                 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);
8546                                 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8547                         }
8548                 }
8549         }
8550 }
8551
8552 void RSurf_DrawBatch(void)
8553 {
8554         // sometimes a zero triangle surface (usually a degenerate patch) makes it
8555         // through the pipeline, killing it earlier in the pipeline would have
8556         // per-surface overhead rather than per-batch overhead, so it's best to
8557         // reject it here, before it hits glDraw.
8558         if (rsurface.batchnumtriangles == 0)
8559                 return;
8560 #if 0
8561         // batch debugging code
8562         if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8563         {
8564                 int i;
8565                 int j;
8566                 int c;
8567                 const int *e;
8568                 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8569                 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8570                 {
8571                         c = e[i];
8572                         for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8573                         {
8574                                 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8575                                 {
8576                                         if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8577                                                 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);
8578                                         break;
8579                                 }
8580                         }
8581                 }
8582         }
8583 #endif
8584         if (rsurface.batchmultidraw)
8585         {
8586                 // issue multiple draws rather than copying index data
8587                 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8588                 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8589                 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8590                 for (i = 0;i < numsurfaces;)
8591                 {
8592                         // combine consecutive surfaces as one draw
8593                         for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8594                                 if (surfacelist[j] != surfacelist[k] + 1)
8595                                         break;
8596                         firstvertex = surfacelist[i]->num_firstvertex;
8597                         endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8598                         firsttriangle = surfacelist[i]->num_firsttriangle;
8599                         endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8600                         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);
8601                         i = j;
8602                 }
8603         }
8604         else
8605         {
8606                 // there is only one consecutive run of index data (may have been combined)
8607                 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);
8608         }
8609 }
8610
8611 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8612 {
8613         // pick the closest matching water plane
8614         int planeindex, vertexindex, bestplaneindex = -1;
8615         float d, bestd;
8616         vec3_t vert;
8617         const float *v;
8618         r_waterstate_waterplane_t *p;
8619         qboolean prepared = false;
8620         bestd = 0;
8621         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8622         {
8623                 if(p->camera_entity != rsurface.texture->camera_entity)
8624                         continue;
8625                 d = 0;
8626                 if(!prepared)
8627                 {
8628                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8629                         prepared = true;
8630                         if(rsurface.batchnumvertices == 0)
8631                                 break;
8632                 }
8633                 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8634                 {
8635                         Matrix4x4_Transform(&rsurface.matrix, v, vert);
8636                         d += fabs(PlaneDiff(vert, &p->plane));
8637                 }
8638                 if (bestd > d || bestplaneindex < 0)
8639                 {
8640                         bestd = d;
8641                         bestplaneindex = planeindex;
8642                 }
8643         }
8644         return bestplaneindex;
8645         // NOTE: this MAY return a totally unrelated water plane; we can ignore
8646         // this situation though, as it might be better to render single larger
8647         // batches with useless stuff (backface culled for example) than to
8648         // render multiple smaller batches
8649 }
8650
8651 void RSurf_SetupDepthAndCulling(void)
8652 {
8653         // submodels are biased to avoid z-fighting with world surfaces that they
8654         // may be exactly overlapping (avoids z-fighting artifacts on certain
8655         // doors and things in Quake maps)
8656         GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8657         GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8658         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8659         GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8660 }
8661
8662 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8663 {
8664         int i, j;
8665         // transparent sky would be ridiculous
8666         if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8667                 return;
8668         R_SetupShader_Generic_NoTexture(false, false);
8669         skyrenderlater = true;
8670         RSurf_SetupDepthAndCulling();
8671         GL_DepthMask(true);
8672
8673         // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8674         if (r_sky_scissor.integer)
8675         {
8676                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8677                 for (i = 0; i < texturenumsurfaces; i++)
8678                 {
8679                         const msurface_t *surf = texturesurfacelist[i];
8680                         const float *v;
8681                         float p[3];
8682                         float mins[3], maxs[3];
8683                         int scissor[4];
8684                         for (j = 0, v = rsurface.batchvertex3f + 3 * surf->num_firstvertex; j < surf->num_vertices; j++, v += 3)
8685                         {
8686                                 Matrix4x4_Transform(&rsurface.matrix, v, p);
8687                                 if (j > 0)
8688                                 {
8689                                         if (mins[0] > p[0]) mins[0] = p[0];
8690                                         if (mins[1] > p[1]) mins[1] = p[1];
8691                                         if (mins[2] > p[2]) mins[2] = p[2];
8692                                         if (maxs[0] < p[0]) maxs[0] = p[0];
8693                                         if (maxs[1] < p[1]) maxs[1] = p[1];
8694                                         if (maxs[2] < p[2]) maxs[2] = p[2];
8695                                 }
8696                                 else
8697                                 {
8698                                         VectorCopy(p, mins);
8699                                         VectorCopy(p, maxs);
8700                                 }
8701                         }
8702                         if (!R_ScissorForBBox(mins, maxs, scissor))
8703                         {
8704                                 if (skyscissor[2])
8705                                 {
8706                                         if (skyscissor[0] > scissor[0])
8707                                         {
8708                                                 skyscissor[2] += skyscissor[0] - scissor[0];
8709                                                 skyscissor[0] = scissor[0];
8710                                         }
8711                                         if (skyscissor[1] > scissor[1])
8712                                         {
8713                                                 skyscissor[3] += skyscissor[1] - scissor[1];
8714                                                 skyscissor[1] = scissor[1];
8715                                         }
8716                                         if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8717                                                 skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8718                                         if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8719                                                 skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8720                                 }
8721                                 else
8722                                         Vector4Copy(scissor, skyscissor);
8723                         }
8724                 }
8725         }
8726
8727         // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8728         // skymasking on them, and Quake3 never did sky masking (unlike
8729         // software Quake and software Quake2), so disable the sky masking
8730         // in Quake3 maps as it causes problems with q3map2 sky tricks,
8731         // and skymasking also looks very bad when noclipping outside the
8732         // level, so don't use it then either.
8733         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)
8734         {
8735                 R_Mesh_ResetTextureState();
8736                 if (skyrendermasked)
8737                 {
8738                         R_SetupShader_DepthOrShadow(false, false, false);
8739                         // depth-only (masking)
8740                         GL_ColorMask(0, 0, 0, 0);
8741                         // just to make sure that braindead drivers don't draw
8742                         // anything despite that colormask...
8743                         GL_BlendFunc(GL_ZERO, GL_ONE);
8744                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8745                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8746                 }
8747                 else
8748                 {
8749                         R_SetupShader_Generic_NoTexture(false, false);
8750                         // fog sky
8751                         GL_BlendFunc(GL_ONE, GL_ZERO);
8752                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8753                         GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
8754                         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
8755                 }
8756                 RSurf_DrawBatch();
8757                 if (skyrendermasked)
8758                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8759         }
8760         R_Mesh_ResetTextureState();
8761         GL_Color(1, 1, 1, 1);
8762 }
8763
8764 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
8765 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
8766 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass, qboolean ui)
8767 {
8768         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
8769                 return;
8770         if (prepass)
8771         {
8772                 // render screenspace normalmap to texture
8773                 GL_DepthMask(true);
8774                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false);
8775                 RSurf_DrawBatch();
8776                 return;
8777         }
8778
8779         // bind lightmap texture
8780
8781         // water/refraction/reflection/camera surfaces have to be handled specially
8782         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
8783         {
8784                 int start, end, startplaneindex;
8785                 for (start = 0;start < texturenumsurfaces;start = end)
8786                 {
8787                         startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
8788                         if(startplaneindex < 0)
8789                         {
8790                                 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
8791                                 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
8792                                 end = start + 1;
8793                                 continue;
8794                         }
8795                         for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
8796                                 ;
8797                         // now that we have a batch using the same planeindex, render it
8798                         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
8799                         {
8800                                 // render water or distortion background
8801                                 GL_DepthMask(true);
8802                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8803                                 RSurf_DrawBatch();
8804                                 // blend surface on top
8805                                 GL_DepthMask(false);
8806                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false);
8807                                 RSurf_DrawBatch();
8808                         }
8809                         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
8810                         {
8811                                 // render surface with reflection texture as input
8812                                 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8813                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8814                                 RSurf_DrawBatch();
8815                         }
8816                 }
8817                 return;
8818         }
8819
8820         // render surface batch normally
8821         GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8822         R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0 || ui);
8823         RSurf_DrawBatch();
8824 }
8825
8826 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
8827 {
8828         int vi;
8829         int j;
8830         int texturesurfaceindex;
8831         int k;
8832         const msurface_t *surface;
8833         float surfacecolor4f[4];
8834
8835 //      R_Mesh_ResetTextureState();
8836         R_SetupShader_Generic_NoTexture(false, false);
8837
8838         GL_BlendFunc(GL_ONE, GL_ZERO);
8839         GL_DepthMask(writedepth);
8840
8841         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
8842         vi = 0;
8843         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8844         {
8845                 surface = texturesurfacelist[texturesurfaceindex];
8846                 k = (int)(((size_t)surface) / sizeof(msurface_t));
8847                 Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
8848                 for (j = 0;j < surface->num_vertices;j++)
8849                 {
8850                         Vector4Copy(surfacecolor4f, rsurface.batchlightmapcolor4f + 4 * vi);
8851                         vi++;
8852                 }
8853         }
8854         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchlightmapcolor4f, rsurface.batchtexcoordtexture2f);
8855         RSurf_DrawBatch();
8856 }
8857
8858 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass, qboolean ui)
8859 {
8860         CHECKGLERROR
8861         RSurf_SetupDepthAndCulling();
8862         if (r_showsurfaces.integer && r_refdef.view.showdebug)
8863         {
8864                 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
8865                 return;
8866         }
8867         switch (vid.renderpath)
8868         {
8869         case RENDERPATH_GL32:
8870         case RENDERPATH_GLES2:
8871                 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8872                 break;
8873         }
8874         CHECKGLERROR
8875 }
8876
8877 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
8878 {
8879         int i, j;
8880         int texturenumsurfaces, endsurface;
8881         texture_t *texture;
8882         const msurface_t *surface;
8883         const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
8884
8885         RSurf_ActiveModelEntity(ent, true, true, false);
8886
8887         if (r_transparentdepthmasking.integer)
8888         {
8889                 qboolean setup = false;
8890                 for (i = 0;i < numsurfaces;i = j)
8891                 {
8892                         j = i + 1;
8893                         surface = rsurface.modelsurfaces + surfacelist[i];
8894                         texture = surface->texture;
8895                         rsurface.texture = R_GetCurrentTexture(texture);
8896                         rsurface.lightmaptexture = NULL;
8897                         rsurface.deluxemaptexture = NULL;
8898                         rsurface.uselightmaptexture = false;
8899                         // scan ahead until we find a different texture
8900                         endsurface = min(i + 1024, numsurfaces);
8901                         texturenumsurfaces = 0;
8902                         texturesurfacelist[texturenumsurfaces++] = surface;
8903                         for (;j < endsurface;j++)
8904                         {
8905                                 surface = rsurface.modelsurfaces + surfacelist[j];
8906                                 if (texture != surface->texture)
8907                                         break;
8908                                 texturesurfacelist[texturenumsurfaces++] = surface;
8909                         }
8910                         if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
8911                                 continue;
8912                         // render the range of surfaces as depth
8913                         if (!setup)
8914                         {
8915                                 setup = true;
8916                                 GL_ColorMask(0,0,0,0);
8917                                 GL_Color(1,1,1,1);
8918                                 GL_DepthTest(true);
8919                                 GL_BlendFunc(GL_ONE, GL_ZERO);
8920                                 GL_DepthMask(true);
8921 //                              R_Mesh_ResetTextureState();
8922                         }
8923                         RSurf_SetupDepthAndCulling();
8924                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8925                         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8926                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8927                         RSurf_DrawBatch();
8928                 }
8929                 if (setup)
8930                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8931         }
8932
8933         for (i = 0;i < numsurfaces;i = j)
8934         {
8935                 j = i + 1;
8936                 surface = rsurface.modelsurfaces + surfacelist[i];
8937                 texture = surface->texture;
8938                 rsurface.texture = R_GetCurrentTexture(texture);
8939                 // scan ahead until we find a different texture
8940                 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
8941                 texturenumsurfaces = 0;
8942                 texturesurfacelist[texturenumsurfaces++] = surface;
8943                         rsurface.lightmaptexture = surface->lightmaptexture;
8944                         rsurface.deluxemaptexture = surface->deluxemaptexture;
8945                         rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
8946                         for (;j < endsurface;j++)
8947                         {
8948                                 surface = rsurface.modelsurfaces + surfacelist[j];
8949                                 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
8950                                         break;
8951                                 texturesurfacelist[texturenumsurfaces++] = surface;
8952                         }
8953                 // render the range of surfaces
8954                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false, false);
8955         }
8956         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
8957 }
8958
8959 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8960 {
8961         // transparent surfaces get pushed off into the transparent queue
8962         int surfacelistindex;
8963         const msurface_t *surface;
8964         vec3_t tempcenter, center;
8965         for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
8966         {
8967                 surface = texturesurfacelist[surfacelistindex];
8968                 if (r_transparent_sortsurfacesbynearest.integer)
8969                 {
8970                         tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
8971                         tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
8972                         tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
8973                 }
8974                 else
8975                 {
8976                         tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
8977                         tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
8978                         tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
8979                 }
8980                 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
8981                 if (rsurface.entity->transparent_offset) // transparent offset
8982                 {
8983                         center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
8984                         center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
8985                         center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
8986                 }
8987                 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);
8988         }
8989 }
8990
8991 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8992 {
8993         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
8994                 return;
8995         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
8996                 return;
8997         RSurf_SetupDepthAndCulling();
8998         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8999         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9000         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9001         RSurf_DrawBatch();
9002 }
9003
9004 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass, qboolean ui)
9005 {
9006         CHECKGLERROR
9007         if (ui)
9008                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
9009         else if (depthonly)
9010                 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
9011         else if (prepass)
9012         {
9013                 if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
9014                         return;
9015                 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
9016                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9017                 else
9018                         R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
9019         }
9020         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
9021                 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
9022         else if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
9023                 return;
9024         else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
9025         {
9026                 // in the deferred case, transparent surfaces were queued during prepass
9027                 if (!r_shadow_usingdeferredprepass)
9028                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9029         }
9030         else
9031         {
9032                 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
9033                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass, ui);
9034         }
9035         CHECKGLERROR
9036 }
9037
9038 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass, qboolean ui)
9039 {
9040         int i, j;
9041         texture_t *texture;
9042         R_FrameData_SetMark();
9043         // break the surface list down into batches by texture and use of lightmapping
9044         for (i = 0;i < numsurfaces;i = j)
9045         {
9046                 j = i + 1;
9047                 // texture is the base texture pointer, rsurface.texture is the
9048                 // current frame/skin the texture is directing us to use (for example
9049                 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
9050                 // use skin 1 instead)
9051                 texture = surfacelist[i]->texture;
9052                 rsurface.texture = R_GetCurrentTexture(texture);
9053                 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
9054                 {
9055                         // if this texture is not the kind we want, skip ahead to the next one
9056                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9057                                 ;
9058                         continue;
9059                 }
9060                 if(depthonly || prepass)
9061                 {
9062                         rsurface.lightmaptexture = NULL;
9063                         rsurface.deluxemaptexture = NULL;
9064                         rsurface.uselightmaptexture = false;
9065                         // simply scan ahead until we find a different texture or lightmap state
9066                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9067                                 ;
9068                 }
9069                 else
9070                 {
9071                         rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
9072                         rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
9073                         rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
9074                         // simply scan ahead until we find a different texture or lightmap state
9075                         for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
9076                                 ;
9077                 }
9078                 // render the range of surfaces
9079                 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass, ui);
9080         }
9081         R_FrameData_ReturnToMark();
9082 }
9083
9084 float locboxvertex3f[6*4*3] =
9085 {
9086         1,0,1, 1,0,0, 1,1,0, 1,1,1,
9087         0,1,1, 0,1,0, 0,0,0, 0,0,1,
9088         1,1,1, 1,1,0, 0,1,0, 0,1,1,
9089         0,0,1, 0,0,0, 1,0,0, 1,0,1,
9090         0,0,1, 1,0,1, 1,1,1, 0,1,1,
9091         1,0,0, 0,0,0, 0,1,0, 1,1,0
9092 };
9093
9094 unsigned short locboxelements[6*2*3] =
9095 {
9096          0, 1, 2, 0, 2, 3,
9097          4, 5, 6, 4, 6, 7,
9098          8, 9,10, 8,10,11,
9099         12,13,14, 12,14,15,
9100         16,17,18, 16,18,19,
9101         20,21,22, 20,22,23
9102 };
9103
9104 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9105 {
9106         int i, j;
9107         cl_locnode_t *loc = (cl_locnode_t *)ent;
9108         vec3_t mins, size;
9109         float vertex3f[6*4*3];
9110         CHECKGLERROR
9111         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9112         GL_DepthMask(false);
9113         GL_DepthRange(0, 1);
9114         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9115         GL_DepthTest(true);
9116         GL_CullFace(GL_NONE);
9117         R_EntityMatrix(&identitymatrix);
9118
9119 //      R_Mesh_ResetTextureState();
9120
9121         i = surfacelist[0];
9122         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9123                          ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9124                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9125                         surfacelist[0] < 0 ? 0.5f : 0.125f);
9126
9127         if (VectorCompare(loc->mins, loc->maxs))
9128         {
9129                 VectorSet(size, 2, 2, 2);
9130                 VectorMA(loc->mins, -0.5f, size, mins);
9131         }
9132         else
9133         {
9134                 VectorCopy(loc->mins, mins);
9135                 VectorSubtract(loc->maxs, loc->mins, size);
9136         }
9137
9138         for (i = 0;i < 6*4*3;)
9139                 for (j = 0;j < 3;j++, i++)
9140                         vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9141
9142         R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9143         R_SetupShader_Generic_NoTexture(false, false);
9144         R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9145 }
9146
9147 void R_DrawLocs(void)
9148 {
9149         int index;
9150         cl_locnode_t *loc, *nearestloc;
9151         vec3_t center;
9152         nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9153         for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9154         {
9155                 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9156                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9157         }
9158 }
9159
9160 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9161 {
9162         if (decalsystem->decals)
9163                 Mem_Free(decalsystem->decals);
9164         memset(decalsystem, 0, sizeof(*decalsystem));
9165 }
9166
9167 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)
9168 {
9169         tridecal_t *decal;
9170         tridecal_t *decals;
9171         int i;
9172
9173         // expand or initialize the system
9174         if (decalsystem->maxdecals <= decalsystem->numdecals)
9175         {
9176                 decalsystem_t old = *decalsystem;
9177                 qboolean useshortelements;
9178                 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9179                 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9180                 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)));
9181                 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9182                 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9183                 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9184                 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9185                 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9186                 if (decalsystem->numdecals)
9187                         memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9188                 if (old.decals)
9189                         Mem_Free(old.decals);
9190                 for (i = 0;i < decalsystem->maxdecals*3;i++)
9191                         decalsystem->element3i[i] = i;
9192                 if (useshortelements)
9193                         for (i = 0;i < decalsystem->maxdecals*3;i++)
9194                                 decalsystem->element3s[i] = i;
9195         }
9196
9197         // grab a decal and search for another free slot for the next one
9198         decals = decalsystem->decals;
9199         decal = decalsystem->decals + (i = decalsystem->freedecal++);
9200         for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9201                 ;
9202         decalsystem->freedecal = i;
9203         if (decalsystem->numdecals <= i)
9204                 decalsystem->numdecals = i + 1;
9205
9206         // initialize the decal
9207         decal->lived = 0;
9208         decal->triangleindex = triangleindex;
9209         decal->surfaceindex = surfaceindex;
9210         decal->decalsequence = decalsequence;
9211         decal->color4f[0][0] = c0[0];
9212         decal->color4f[0][1] = c0[1];
9213         decal->color4f[0][2] = c0[2];
9214         decal->color4f[0][3] = 1;
9215         decal->color4f[1][0] = c1[0];
9216         decal->color4f[1][1] = c1[1];
9217         decal->color4f[1][2] = c1[2];
9218         decal->color4f[1][3] = 1;
9219         decal->color4f[2][0] = c2[0];
9220         decal->color4f[2][1] = c2[1];
9221         decal->color4f[2][2] = c2[2];
9222         decal->color4f[2][3] = 1;
9223         decal->vertex3f[0][0] = v0[0];
9224         decal->vertex3f[0][1] = v0[1];
9225         decal->vertex3f[0][2] = v0[2];
9226         decal->vertex3f[1][0] = v1[0];
9227         decal->vertex3f[1][1] = v1[1];
9228         decal->vertex3f[1][2] = v1[2];
9229         decal->vertex3f[2][0] = v2[0];
9230         decal->vertex3f[2][1] = v2[1];
9231         decal->vertex3f[2][2] = v2[2];
9232         decal->texcoord2f[0][0] = t0[0];
9233         decal->texcoord2f[0][1] = t0[1];
9234         decal->texcoord2f[1][0] = t1[0];
9235         decal->texcoord2f[1][1] = t1[1];
9236         decal->texcoord2f[2][0] = t2[0];
9237         decal->texcoord2f[2][1] = t2[1];
9238         TriangleNormal(v0, v1, v2, decal->plane);
9239         VectorNormalize(decal->plane);
9240         decal->plane[3] = DotProduct(v0, decal->plane);
9241 }
9242
9243 extern cvar_t cl_decals_bias;
9244 extern cvar_t cl_decals_models;
9245 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9246 // baseparms, parms, temps
9247 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)
9248 {
9249         int cornerindex;
9250         int index;
9251         float v[9][3];
9252         const float *vertex3f;
9253         const float *normal3f;
9254         int numpoints;
9255         float points[2][9][3];
9256         float temp[3];
9257         float tc[9][2];
9258         float f;
9259         float c[9][4];
9260         const int *e;
9261
9262         e = rsurface.modelelement3i + 3*triangleindex;
9263
9264         vertex3f = rsurface.modelvertex3f;
9265         normal3f = rsurface.modelnormal3f;
9266
9267         if (normal3f)
9268         {
9269                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9270                 {
9271                         index = 3*e[cornerindex];
9272                         VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9273                 }
9274         }
9275         else
9276         {
9277                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9278                 {
9279                         index = 3*e[cornerindex];
9280                         VectorCopy(vertex3f + index, v[cornerindex]);
9281                 }
9282         }
9283
9284         // cull backfaces
9285         //TriangleNormal(v[0], v[1], v[2], normal);
9286         //if (DotProduct(normal, localnormal) < 0.0f)
9287         //      continue;
9288         // clip by each of the box planes formed from the projection matrix
9289         // if anything survives, we emit the decal
9290         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]);
9291         if (numpoints < 3)
9292                 return;
9293         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]);
9294         if (numpoints < 3)
9295                 return;
9296         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]);
9297         if (numpoints < 3)
9298                 return;
9299         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]);
9300         if (numpoints < 3)
9301                 return;
9302         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]);
9303         if (numpoints < 3)
9304                 return;
9305         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]);
9306         if (numpoints < 3)
9307                 return;
9308         // some part of the triangle survived, so we have to accept it...
9309         if (dynamic)
9310         {
9311                 // dynamic always uses the original triangle
9312                 numpoints = 3;
9313                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9314                 {
9315                         index = 3*e[cornerindex];
9316                         VectorCopy(vertex3f + index, v[cornerindex]);
9317                 }
9318         }
9319         for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9320         {
9321                 // convert vertex positions to texcoords
9322                 Matrix4x4_Transform(projection, v[cornerindex], temp);
9323                 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9324                 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9325                 // calculate distance fade from the projection origin
9326                 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9327                 f = bound(0.0f, f, 1.0f);
9328                 c[cornerindex][0] = r * f;
9329                 c[cornerindex][1] = g * f;
9330                 c[cornerindex][2] = b * f;
9331                 c[cornerindex][3] = 1.0f;
9332                 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9333         }
9334         if (dynamic)
9335                 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);
9336         else
9337                 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9338                         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);
9339 }
9340 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)
9341 {
9342         matrix4x4_t projection;
9343         decalsystem_t *decalsystem;
9344         qboolean dynamic;
9345         dp_model_t *model;
9346         const msurface_t *surface;
9347         const msurface_t *surfaces;
9348         const int *surfacelist;
9349         const texture_t *texture;
9350         int numtriangles;
9351         int numsurfacelist;
9352         int surfacelistindex;
9353         int surfaceindex;
9354         int triangleindex;
9355         float localorigin[3];
9356         float localnormal[3];
9357         float localmins[3];
9358         float localmaxs[3];
9359         float localsize;
9360         //float normal[3];
9361         float planes[6][4];
9362         float angles[3];
9363         bih_t *bih;
9364         int bih_triangles_count;
9365         int bih_triangles[256];
9366         int bih_surfaces[256];
9367
9368         decalsystem = &ent->decalsystem;
9369         model = ent->model;
9370         if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9371         {
9372                 R_DecalSystem_Reset(&ent->decalsystem);
9373                 return;
9374         }
9375
9376         if (!model->brush.data_leafs && !cl_decals_models.integer)
9377         {
9378                 if (decalsystem->model)
9379                         R_DecalSystem_Reset(decalsystem);
9380                 return;
9381         }
9382
9383         if (decalsystem->model != model)
9384                 R_DecalSystem_Reset(decalsystem);
9385         decalsystem->model = model;
9386
9387         RSurf_ActiveModelEntity(ent, true, false, false);
9388
9389         Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9390         Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9391         VectorNormalize(localnormal);
9392         localsize = worldsize*rsurface.inversematrixscale;
9393         localmins[0] = localorigin[0] - localsize;
9394         localmins[1] = localorigin[1] - localsize;
9395         localmins[2] = localorigin[2] - localsize;
9396         localmaxs[0] = localorigin[0] + localsize;
9397         localmaxs[1] = localorigin[1] + localsize;
9398         localmaxs[2] = localorigin[2] + localsize;
9399
9400         //VectorCopy(localnormal, planes[4]);
9401         //VectorVectors(planes[4], planes[2], planes[0]);
9402         AnglesFromVectors(angles, localnormal, NULL, false);
9403         AngleVectors(angles, planes[0], planes[2], planes[4]);
9404         VectorNegate(planes[0], planes[1]);
9405         VectorNegate(planes[2], planes[3]);
9406         VectorNegate(planes[4], planes[5]);
9407         planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9408         planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9409         planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9410         planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9411         planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9412         planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9413
9414 #if 1
9415 // works
9416 {
9417         matrix4x4_t forwardprojection;
9418         Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9419         Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9420 }
9421 #else
9422 // broken
9423 {
9424         float projectionvector[4][3];
9425         VectorScale(planes[0], ilocalsize, projectionvector[0]);
9426         VectorScale(planes[2], ilocalsize, projectionvector[1]);
9427         VectorScale(planes[4], ilocalsize, projectionvector[2]);
9428         projectionvector[0][0] = planes[0][0] * ilocalsize;
9429         projectionvector[0][1] = planes[1][0] * ilocalsize;
9430         projectionvector[0][2] = planes[2][0] * ilocalsize;
9431         projectionvector[1][0] = planes[0][1] * ilocalsize;
9432         projectionvector[1][1] = planes[1][1] * ilocalsize;
9433         projectionvector[1][2] = planes[2][1] * ilocalsize;
9434         projectionvector[2][0] = planes[0][2] * ilocalsize;
9435         projectionvector[2][1] = planes[1][2] * ilocalsize;
9436         projectionvector[2][2] = planes[2][2] * ilocalsize;
9437         projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9438         projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9439         projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9440         Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9441 }
9442 #endif
9443
9444         dynamic = model->surfmesh.isanimated;
9445         numsurfacelist = model->nummodelsurfaces;
9446         surfacelist = model->sortedmodelsurfaces;
9447         surfaces = model->data_surfaces;
9448
9449         bih = NULL;
9450         bih_triangles_count = -1;
9451         if(!dynamic)
9452         {
9453                 if(model->render_bih.numleafs)
9454                         bih = &model->render_bih;
9455                 else if(model->collision_bih.numleafs)
9456                         bih = &model->collision_bih;
9457         }
9458         if(bih)
9459                 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9460         if(bih_triangles_count == 0)
9461                 return;
9462         if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9463                 return;
9464         if(bih_triangles_count > 0)
9465         {
9466                 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9467                 {
9468                         surfaceindex = bih_surfaces[triangleindex];
9469                         surface = surfaces + surfaceindex;
9470                         texture = surface->texture;
9471                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9472                                 continue;
9473                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9474                                 continue;
9475                         R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9476                 }
9477         }
9478         else
9479         {
9480                 for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
9481                 {
9482                         surfaceindex = surfacelist[surfacelistindex];
9483                         surface = surfaces + surfaceindex;
9484                         // check cull box first because it rejects more than any other check
9485                         if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9486                                 continue;
9487                         // skip transparent surfaces
9488                         texture = surface->texture;
9489                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9490                                 continue;
9491                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9492                                 continue;
9493                         numtriangles = surface->num_triangles;
9494                         for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9495                                 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9496                 }
9497         }
9498 }
9499
9500 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9501 static void R_DecalSystem_ApplySplatEntities(const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize, unsigned int decalsequence)
9502 {
9503         int renderentityindex;
9504         float worldmins[3];
9505         float worldmaxs[3];
9506         entity_render_t *ent;
9507
9508         worldmins[0] = worldorigin[0] - worldsize;
9509         worldmins[1] = worldorigin[1] - worldsize;
9510         worldmins[2] = worldorigin[2] - worldsize;
9511         worldmaxs[0] = worldorigin[0] + worldsize;
9512         worldmaxs[1] = worldorigin[1] + worldsize;
9513         worldmaxs[2] = worldorigin[2] + worldsize;
9514
9515         R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9516
9517         for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9518         {
9519                 ent = r_refdef.scene.entities[renderentityindex];
9520                 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9521                         continue;
9522
9523                 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9524         }
9525 }
9526
9527 typedef struct r_decalsystem_splatqueue_s
9528 {
9529         vec3_t worldorigin;
9530         vec3_t worldnormal;
9531         float color[4];
9532         float tcrange[4];
9533         float worldsize;
9534         unsigned int decalsequence;
9535 }
9536 r_decalsystem_splatqueue_t;
9537
9538 int r_decalsystem_numqueued = 0;
9539 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9540
9541 void R_DecalSystem_SplatEntities(const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize)
9542 {
9543         r_decalsystem_splatqueue_t *queue;
9544
9545         if (r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9546                 return;
9547
9548         queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9549         VectorCopy(worldorigin, queue->worldorigin);
9550         VectorCopy(worldnormal, queue->worldnormal);
9551         Vector4Set(queue->color, r, g, b, a);
9552         Vector4Set(queue->tcrange, s1, t1, s2, t2);
9553         queue->worldsize = worldsize;
9554         queue->decalsequence = cl.decalsequence++;
9555 }
9556
9557 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9558 {
9559         int i;
9560         r_decalsystem_splatqueue_t *queue;
9561
9562         for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9563                 R_DecalSystem_ApplySplatEntities(queue->worldorigin, queue->worldnormal, queue->color[0], queue->color[1], queue->color[2], queue->color[3], queue->tcrange[0], queue->tcrange[1], queue->tcrange[2], queue->tcrange[3], queue->worldsize, queue->decalsequence);
9564         r_decalsystem_numqueued = 0;
9565 }
9566
9567 extern cvar_t cl_decals_max;
9568 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9569 {
9570         int i;
9571         decalsystem_t *decalsystem = &ent->decalsystem;
9572         int numdecals;
9573         unsigned int killsequence;
9574         tridecal_t *decal;
9575         float frametime;
9576         float lifetime;
9577
9578         if (!decalsystem->numdecals)
9579                 return;
9580
9581         if (r_showsurfaces.integer)
9582                 return;
9583
9584         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9585         {
9586                 R_DecalSystem_Reset(decalsystem);
9587                 return;
9588         }
9589
9590         killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9591         lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9592
9593         if (decalsystem->lastupdatetime)
9594                 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9595         else
9596                 frametime = 0;
9597         decalsystem->lastupdatetime = r_refdef.scene.time;
9598         numdecals = decalsystem->numdecals;
9599
9600         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9601         {
9602                 if (decal->color4f[0][3])
9603                 {
9604                         decal->lived += frametime;
9605                         if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9606                         {
9607                                 memset(decal, 0, sizeof(*decal));
9608                                 if (decalsystem->freedecal > i)
9609                                         decalsystem->freedecal = i;
9610                         }
9611                 }
9612         }
9613         decal = decalsystem->decals;
9614         while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9615                 numdecals--;
9616
9617         // collapse the array by shuffling the tail decals into the gaps
9618         for (;;)
9619         {
9620                 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
9621                         decalsystem->freedecal++;
9622                 if (decalsystem->freedecal == numdecals)
9623                         break;
9624                 decal[decalsystem->freedecal] = decal[--numdecals];
9625         }
9626
9627         decalsystem->numdecals = numdecals;
9628
9629         if (numdecals <= 0)
9630         {
9631                 // if there are no decals left, reset decalsystem
9632                 R_DecalSystem_Reset(decalsystem);
9633         }
9634 }
9635
9636 extern skinframe_t *decalskinframe;
9637 static void R_DrawModelDecals_Entity(entity_render_t *ent)
9638 {
9639         int i;
9640         decalsystem_t *decalsystem = &ent->decalsystem;
9641         int numdecals;
9642         tridecal_t *decal;
9643         float faderate;
9644         float alpha;
9645         float *v3f;
9646         float *c4f;
9647         float *t2f;
9648         const int *e;
9649         const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
9650         int numtris = 0;
9651
9652         numdecals = decalsystem->numdecals;
9653         if (!numdecals)
9654                 return;
9655
9656         if (r_showsurfaces.integer)
9657                 return;
9658
9659         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9660         {
9661                 R_DecalSystem_Reset(decalsystem);
9662                 return;
9663         }
9664
9665         // if the model is static it doesn't matter what value we give for
9666         // wantnormals and wanttangents, so this logic uses only rules applicable
9667         // to a model, knowing that they are meaningless otherwise
9668         RSurf_ActiveModelEntity(ent, false, false, false);
9669
9670         decalsystem->lastupdatetime = r_refdef.scene.time;
9671
9672         faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
9673
9674         // update vertex positions for animated models
9675         v3f = decalsystem->vertex3f;
9676         c4f = decalsystem->color4f;
9677         t2f = decalsystem->texcoord2f;
9678         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9679         {
9680                 if (!decal->color4f[0][3])
9681                         continue;
9682
9683                 if (surfacevisible && !surfacevisible[decal->surfaceindex])
9684                         continue;
9685
9686                 // skip backfaces
9687                 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
9688                         continue;
9689
9690                 // update color values for fading decals
9691                 if (decal->lived >= cl_decals_time.value)
9692                         alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
9693                 else
9694                         alpha = 1.0f;
9695
9696                 c4f[ 0] = decal->color4f[0][0] * alpha;
9697                 c4f[ 1] = decal->color4f[0][1] * alpha;
9698                 c4f[ 2] = decal->color4f[0][2] * alpha;
9699                 c4f[ 3] = 1;
9700                 c4f[ 4] = decal->color4f[1][0] * alpha;
9701                 c4f[ 5] = decal->color4f[1][1] * alpha;
9702                 c4f[ 6] = decal->color4f[1][2] * alpha;
9703                 c4f[ 7] = 1;
9704                 c4f[ 8] = decal->color4f[2][0] * alpha;
9705                 c4f[ 9] = decal->color4f[2][1] * alpha;
9706                 c4f[10] = decal->color4f[2][2] * alpha;
9707                 c4f[11] = 1;
9708
9709                 t2f[0] = decal->texcoord2f[0][0];
9710                 t2f[1] = decal->texcoord2f[0][1];
9711                 t2f[2] = decal->texcoord2f[1][0];
9712                 t2f[3] = decal->texcoord2f[1][1];
9713                 t2f[4] = decal->texcoord2f[2][0];
9714                 t2f[5] = decal->texcoord2f[2][1];
9715
9716                 // update vertex positions for animated models
9717                 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
9718                 {
9719                         e = rsurface.modelelement3i + 3*decal->triangleindex;
9720                         VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
9721                         VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
9722                         VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
9723                 }
9724                 else
9725                 {
9726                         VectorCopy(decal->vertex3f[0], v3f);
9727                         VectorCopy(decal->vertex3f[1], v3f + 3);
9728                         VectorCopy(decal->vertex3f[2], v3f + 6);
9729                 }
9730
9731                 if (r_refdef.fogenabled)
9732                 {
9733                         alpha = RSurf_FogVertex(v3f);
9734                         VectorScale(c4f, alpha, c4f);
9735                         alpha = RSurf_FogVertex(v3f + 3);
9736                         VectorScale(c4f + 4, alpha, c4f + 4);
9737                         alpha = RSurf_FogVertex(v3f + 6);
9738                         VectorScale(c4f + 8, alpha, c4f + 8);
9739                 }
9740
9741                 v3f += 9;
9742                 c4f += 12;
9743                 t2f += 6;
9744                 numtris++;
9745         }
9746
9747         if (numtris > 0)
9748         {
9749                 r_refdef.stats[r_stat_drawndecals] += numtris;
9750
9751                 // now render the decals all at once
9752                 // (this assumes they all use one particle font texture!)
9753                 RSurf_ActiveCustomEntity(&rsurface.matrix, &rsurface.inversematrix, rsurface.ent_flags, ent->shadertime, 1, 1, 1, 1, numdecals*3, decalsystem->vertex3f, decalsystem->texcoord2f, NULL, NULL, NULL, decalsystem->color4f, numtris, decalsystem->element3i, decalsystem->element3s, false, false);
9754 //              R_Mesh_ResetTextureState();
9755                 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
9756                 GL_DepthMask(false);
9757                 GL_DepthRange(0, 1);
9758                 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
9759                 GL_DepthTest(true);
9760                 GL_CullFace(GL_NONE);
9761                 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
9762                 R_SetupShader_Generic(decalskinframe->base, false, false, false);
9763                 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
9764         }
9765 }
9766
9767 static void R_DrawModelDecals(void)
9768 {
9769         int i, numdecals;
9770
9771         // fade faster when there are too many decals
9772         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9773         for (i = 0;i < r_refdef.scene.numentities;i++)
9774                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9775
9776         R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
9777         for (i = 0;i < r_refdef.scene.numentities;i++)
9778                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9779                         R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
9780
9781         R_DecalSystem_ApplySplatEntitiesQueue();
9782
9783         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9784         for (i = 0;i < r_refdef.scene.numentities;i++)
9785                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9786
9787         r_refdef.stats[r_stat_totaldecals] += numdecals;
9788
9789         if (r_showsurfaces.integer || !r_drawdecals.integer)
9790                 return;
9791
9792         R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
9793
9794         for (i = 0;i < r_refdef.scene.numentities;i++)
9795         {
9796                 if (!r_refdef.viewcache.entityvisible[i])
9797                         continue;
9798                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9799                         R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
9800         }
9801 }
9802
9803 extern cvar_t mod_collision_bih;
9804 static void R_DrawDebugModel(void)
9805 {
9806         entity_render_t *ent = rsurface.entity;
9807         int i, j, flagsmask;
9808         const msurface_t *surface;
9809         dp_model_t *model = ent->model;
9810
9811         if (!sv.active  && !cls.demoplayback && ent != r_refdef.scene.worldentity)
9812                 return;
9813
9814         if (r_showoverdraw.value > 0)
9815         {
9816                 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
9817                 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9818                 R_SetupShader_Generic_NoTexture(false, false);
9819                 GL_DepthTest(false);
9820                 GL_DepthMask(false);
9821                 GL_DepthRange(0, 1);
9822                 GL_BlendFunc(GL_ONE, GL_ONE);
9823                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9824                 {
9825                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9826                                 continue;
9827                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9828                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9829                         {
9830                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
9831                                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
9832                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9833                                         GL_Color(c, 0, 0, 1.0f);
9834                                 else if (ent == r_refdef.scene.worldentity)
9835                                         GL_Color(c, c, c, 1.0f);
9836                                 else
9837                                         GL_Color(0, c, 0, 1.0f);
9838                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9839                                 RSurf_DrawBatch();
9840                         }
9841                 }
9842                 rsurface.texture = NULL;
9843         }
9844
9845         flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9846
9847 //      R_Mesh_ResetTextureState();
9848         R_SetupShader_Generic_NoTexture(false, false);
9849         GL_DepthRange(0, 1);
9850         GL_DepthTest(!r_showdisabledepthtest.integer);
9851         GL_DepthMask(false);
9852         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9853
9854         if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
9855         {
9856                 int triangleindex;
9857                 int bihleafindex;
9858                 qboolean cullbox = false;
9859                 const q3mbrush_t *brush;
9860                 const bih_t *bih = &model->collision_bih;
9861                 const bih_leaf_t *bihleaf;
9862                 float vertex3f[3][3];
9863                 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
9864                 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
9865                 {
9866                         if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
9867                                 continue;
9868                         switch (bihleaf->type)
9869                         {
9870                         case BIH_BRUSH:
9871                                 brush = model->brush.data_brushes + bihleaf->itemindex;
9872                                 if (brush->colbrushf && brush->colbrushf->numtriangles)
9873                                 {
9874                                         GL_Color((bihleafindex & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value);
9875                                         R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
9876                                         R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
9877                                 }
9878                                 break;
9879                         case BIH_COLLISIONTRIANGLE:
9880                                 triangleindex = bihleaf->itemindex;
9881                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
9882                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
9883                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
9884                                 GL_Color((bihleafindex & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value);
9885                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9886                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9887                                 break;
9888                         case BIH_RENDERTRIANGLE:
9889                                 triangleindex = bihleaf->itemindex;
9890                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
9891                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
9892                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
9893                                 GL_Color((bihleafindex & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value);
9894                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9895                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9896                                 break;
9897                         }
9898                 }
9899         }
9900
9901         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9902
9903 #ifndef USE_GLES2
9904         if (r_showtris.value > 0 && qglPolygonMode)
9905         {
9906                 if (r_showdisabledepthtest.integer)
9907                 {
9908                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9909                         GL_DepthMask(false);
9910                 }
9911                 else
9912                 {
9913                         GL_BlendFunc(GL_ONE, GL_ZERO);
9914                         GL_DepthMask(true);
9915                 }
9916                 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
9917                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9918                 {
9919                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9920                                 continue;
9921                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9922                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9923                         {
9924                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9925                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9926                                         GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
9927                                 else if (ent == r_refdef.scene.worldentity)
9928                                         GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
9929                                 else
9930                                         GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
9931                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9932                                 RSurf_DrawBatch();
9933                         }
9934                 }
9935                 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
9936                 rsurface.texture = NULL;
9937         }
9938
9939 # if 0
9940         // FIXME!  implement r_shownormals with just triangles
9941         if (r_shownormals.value != 0 && qglBegin)
9942         {
9943                 int l, k;
9944                 vec3_t v;
9945                 if (r_showdisabledepthtest.integer)
9946                 {
9947                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9948                         GL_DepthMask(false);
9949                 }
9950                 else
9951                 {
9952                         GL_BlendFunc(GL_ONE, GL_ZERO);
9953                         GL_DepthMask(true);
9954                 }
9955                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9956                 {
9957                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9958                                 continue;
9959                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9960                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9961                         {
9962                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9963                                 qglBegin(GL_LINES);
9964                                 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
9965                                 {
9966                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9967                                         {
9968                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9969                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9970                                                 qglVertex3f(v[0], v[1], v[2]);
9971                                                 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9972                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9973                                                 qglVertex3f(v[0], v[1], v[2]);
9974                                         }
9975                                 }
9976                                 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
9977                                 {
9978                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9979                                         {
9980                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9981                                                 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
9982                                                 qglVertex3f(v[0], v[1], v[2]);
9983                                                 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
9984                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9985                                                 qglVertex3f(v[0], v[1], v[2]);
9986                                         }
9987                                 }
9988                                 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
9989                                 {
9990                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9991                                         {
9992                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9993                                                 GL_Color(0, r_refdef.view.colorscale, 0, 1);
9994                                                 qglVertex3f(v[0], v[1], v[2]);
9995                                                 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
9996                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9997                                                 qglVertex3f(v[0], v[1], v[2]);
9998                                         }
9999                                 }
10000                                 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
10001                                 {
10002                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10003                                         {
10004                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10005                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10006                                                 qglVertex3f(v[0], v[1], v[2]);
10007                                                 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10008                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10009                                                 qglVertex3f(v[0], v[1], v[2]);
10010                                         }
10011                                 }
10012                                 qglEnd();
10013                                 CHECKGLERROR
10014                         }
10015                 }
10016                 rsurface.texture = NULL;
10017         }
10018 # endif
10019 #endif
10020 }
10021
10022 int r_maxsurfacelist = 0;
10023 const msurface_t **r_surfacelist = NULL;
10024 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass, qboolean ui)
10025 {
10026         int i, j, endj, flagsmask;
10027         dp_model_t *model = ent->model;
10028         msurface_t *surfaces;
10029         unsigned char *update;
10030         int numsurfacelist = 0;
10031         if (model == NULL)
10032                 return;
10033
10034         if (r_maxsurfacelist < model->num_surfaces)
10035         {
10036                 r_maxsurfacelist = model->num_surfaces;
10037                 if (r_surfacelist)
10038                         Mem_Free((msurface_t **)r_surfacelist);
10039                 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
10040         }
10041
10042         if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
10043                 RSurf_ActiveModelEntity(ent, false, false, false);
10044         else if (prepass)
10045                 RSurf_ActiveModelEntity(ent, true, true, true);
10046         else if (depthonly)
10047                 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
10048         else
10049                 RSurf_ActiveModelEntity(ent, true, true, false);
10050
10051         surfaces = model->data_surfaces;
10052         update = model->brushq1.lightmapupdateflags;
10053
10054         // update light styles
10055         if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0)
10056         {
10057                 model_brush_lightstyleinfo_t *style;
10058                 for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
10059                 {
10060                         if (style->value != r_refdef.scene.lightstylevalue[style->style])
10061                         {
10062                                 int *list = style->surfacelist;
10063                                 style->value = r_refdef.scene.lightstylevalue[style->style];
10064                                 for (j = 0;j < style->numsurfaces;j++)
10065                                         update[list[j]] = true;
10066                         }
10067                 }
10068         }
10069
10070         flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
10071
10072         if (debug)
10073         {
10074                 R_DrawDebugModel();
10075                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10076                 return;
10077         }
10078
10079         rsurface.lightmaptexture = NULL;
10080         rsurface.deluxemaptexture = NULL;
10081         rsurface.uselightmaptexture = false;
10082         rsurface.texture = NULL;
10083         rsurface.rtlight = NULL;
10084         numsurfacelist = 0;
10085         // add visible surfaces to draw list
10086         if (ent == r_refdef.scene.worldentity)
10087         {
10088                 // for the world entity, check surfacevisible
10089                 for (i = 0;i < model->nummodelsurfaces;i++)
10090                 {
10091                         j = model->sortedmodelsurfaces[i];
10092                         if (r_refdef.viewcache.world_surfacevisible[j])
10093                                 r_surfacelist[numsurfacelist++] = surfaces + j;
10094                 }
10095         }
10096         else if (ui)
10097         {
10098                 // for ui we have to preserve the order of surfaces
10099                 for (i = 0; i < model->nummodelsurfaces; i++)
10100                         r_surfacelist[numsurfacelist++] = surfaces + model->firstmodelsurface + i;
10101         }
10102         else
10103         {
10104                 // add all surfaces
10105                 for (i = 0; i < model->nummodelsurfaces; i++)
10106                         r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
10107         }
10108         // don't do anything if there were no surfaces
10109         if (!numsurfacelist)
10110         {
10111                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10112                 return;
10113         }
10114         // update lightmaps if needed
10115         if (update)
10116         {
10117                 int updated = 0;
10118                 for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
10119                 {
10120                         if (update[j])
10121                         {
10122                                 updated++;
10123                                 R_BuildLightMap(ent, surfaces + j);
10124                         }
10125                 }
10126         }
10127
10128         R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass, ui);
10129
10130         // add to stats if desired
10131         if (r_speeds.integer && !skysurfaces && !depthonly)
10132         {
10133                 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10134                 for (j = 0;j < numsurfacelist;j++)
10135                         r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10136         }
10137
10138         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10139 }
10140
10141 void R_DebugLine(vec3_t start, vec3_t end)
10142 {
10143         dp_model_t *mod = CL_Mesh_UI();
10144         msurface_t *surf;
10145         int e0, e1, e2, e3;
10146         float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10147         float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10148         float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10149         vec4_t w[2], s[2];
10150
10151         // transform to screen coords first
10152         Vector4Set(w[0], start[0], start[1], start[2], 1);
10153         Vector4Set(w[1], end[0], end[1], end[2], 1);
10154         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10155         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10156         x1 = s[0][0] * vid_conwidth.value / vid.width;
10157         y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10158         x2 = s[1][0] * vid_conwidth.value / vid.width;
10159         y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10160         //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10161
10162         // add the line to the UI mesh for drawing later
10163
10164         // width is measured in real pixels
10165         if (fabs(x2 - x1) > fabs(y2 - y1))
10166         {
10167                 offsetx = 0;
10168                 offsety = 0.5f * width * vid_conheight.value / vid.height;
10169         }
10170         else
10171         {
10172                 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10173                 offsety = 0;
10174         }
10175         surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_WALL | MATERIALFLAG_VERTEXCOLOR | MATERIALFLAG_ALPHAGEN_VERTEX | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW), true);
10176         e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10177         e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10178         e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10179         e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10180         Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10181         Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10182
10183 }
10184
10185
10186 void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass, qboolean ui)
10187 {
10188         static texture_t texture;
10189
10190         // fake enough texture and surface state to render this geometry
10191
10192         texture.update_lastrenderframe = -1; // regenerate this texture
10193         texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10194         texture.basealpha = 1.0f;
10195         texture.currentskinframe = skinframe;
10196         texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10197         texture.offsetmapping = OFFSETMAPPING_OFF;
10198         texture.offsetscale = 1;
10199         texture.specularscalemod = 1;
10200         texture.specularpowermod = 1;
10201         texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10202
10203         R_DrawCustomSurface_Texture(&texture, texmatrix, materialflags, firstvertex, numvertices, firsttriangle, numtriangles, writedepth, prepass, ui);
10204 }
10205
10206 void R_DrawCustomSurface_Texture(texture_t *texture, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass, qboolean ui)
10207 {
10208         static msurface_t surface;
10209         const msurface_t *surfacelist = &surface;
10210
10211         // fake enough texture and surface state to render this geometry
10212         surface.texture = texture;
10213         surface.num_triangles = numtriangles;
10214         surface.num_firsttriangle = firsttriangle;
10215         surface.num_vertices = numvertices;
10216         surface.num_firstvertex = firstvertex;
10217
10218         // now render it
10219         rsurface.texture = R_GetCurrentTexture(surface.texture);
10220         rsurface.lightmaptexture = NULL;
10221         rsurface.deluxemaptexture = NULL;
10222         rsurface.uselightmaptexture = false;
10223         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass, ui);
10224 }