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