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