]> git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
Reset r_shadow_occlusion_buf on vid_restart. Fixes query buffer dangling pointer
[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 cvar_t r_colorfringe = {CVAR_CLIENT | CVAR_SAVE, "r_colorfringe", "0", "Chromatic aberration. Values higher than 0.025 will noticeably distort the image"};
194
195 cvar_t r_water = {CVAR_CLIENT | CVAR_SAVE, "r_water", "0", "whether to use reflections and refraction on water surfaces (note: r_wateralpha must be set below 1)"};
196 cvar_t r_water_cameraentitiesonly = {CVAR_CLIENT | CVAR_SAVE, "r_water_cameraentitiesonly", "0", "whether to only show QC-defined reflections/refractions (typically used for camera- or portal-like effects)"};
197 cvar_t r_water_clippingplanebias = {CVAR_CLIENT | CVAR_SAVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
198 cvar_t r_water_resolutionmultiplier = {CVAR_CLIENT | CVAR_SAVE, "r_water_resolutionmultiplier", "0.5", "multiplier for screen resolution when rendering refracted/reflected scenes, 1 is full quality, lower values are faster"};
199 cvar_t r_water_refractdistort = {CVAR_CLIENT | CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
200 cvar_t r_water_reflectdistort = {CVAR_CLIENT | CVAR_SAVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
201 cvar_t r_water_scissormode = {CVAR_CLIENT, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
202 cvar_t r_water_lowquality = {CVAR_CLIENT, "r_water_lowquality", "0", "special option to accelerate water rendering: 1 disables all dynamic lights, 2 disables particles too"};
203 cvar_t r_water_hideplayer = {CVAR_CLIENT | CVAR_SAVE, "r_water_hideplayer", "0", "if set to 1 then player will be hidden in refraction views, if set to 2 then player will also be hidden in reflection views, player is always visible in camera views"};
204
205 cvar_t r_lerpsprites = {CVAR_CLIENT | CVAR_SAVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"};
206 cvar_t r_lerpmodels = {CVAR_CLIENT | CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
207 cvar_t r_lerplightstyles = {CVAR_CLIENT | CVAR_SAVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
208 cvar_t r_waterscroll = {CVAR_CLIENT | CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
209
210 cvar_t r_bloom = {CVAR_CLIENT | CVAR_SAVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
211 cvar_t r_bloom_colorscale = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorscale", "1", "how bright the glow is"};
212
213 cvar_t r_bloom_brighten = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_brighten", "2", "how bright the glow is, after subtract/power"};
214 cvar_t r_bloom_blur = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_blur", "4", "how large the glow is"};
215 cvar_t r_bloom_resolution = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
216 cvar_t r_bloom_colorexponent = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorexponent", "1", "how exaggerated the glow is"};
217 cvar_t r_bloom_colorsubtract = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorsubtract", "0.125", "reduces bloom colors by a certain amount"};
218 cvar_t r_bloom_scenebrightness = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_scenebrightness", "1", "global rendering brightness when bloom is enabled"};
219
220 cvar_t r_hdr_scenebrightness = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
221 cvar_t r_hdr_glowintensity = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
222 cvar_t r_hdr_irisadaptation = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation", "0", "adjust scene brightness according to light intensity at player location"};
223 cvar_t r_hdr_irisadaptation_multiplier = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_multiplier", "2", "brightness at which value will be 1.0"};
224 cvar_t r_hdr_irisadaptation_minvalue = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_minvalue", "0.5", "minimum value that can result from multiplier / brightness"};
225 cvar_t r_hdr_irisadaptation_maxvalue = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_maxvalue", "4", "maximum value that can result from multiplier / brightness"};
226 cvar_t r_hdr_irisadaptation_value = {CVAR_CLIENT, "r_hdr_irisadaptation_value", "1", "current value as scenebrightness multiplier, changes continuously when irisadaptation is active"};
227 cvar_t r_hdr_irisadaptation_fade_up = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_fade_up", "0.1", "fade rate at which value adjusts to darkness"};
228 cvar_t r_hdr_irisadaptation_fade_down = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_fade_down", "0.5", "fade rate at which value adjusts to brightness"};
229 cvar_t r_hdr_irisadaptation_radius = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_radius", "15", "lighting within this many units of the eye is averaged"};
230
231 cvar_t r_smoothnormals_areaweighting = {CVAR_CLIENT, "r_smoothnormals_areaweighting", "1", "uses significantly faster (and supposedly higher quality) area-weighted vertex normals and tangent vectors rather than summing normalized triangle normals and tangents"};
232
233 cvar_t developer_texturelogging = {CVAR_CLIENT, "developer_texturelogging", "0", "produces a textures.log file containing names of skins and map textures the engine tried to load"};
234
235 cvar_t gl_lightmaps = {CVAR_CLIENT, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers), a value of 2 keeps normalmap shading"};
236
237 cvar_t r_test = {CVAR_CLIENT, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
238
239 cvar_t r_batch_multidraw = {CVAR_CLIENT | CVAR_SAVE, "r_batch_multidraw", "1", "issue multiple glDrawElements calls when rendering a batch of surfaces with the same texture (otherwise the index data is copied to make it one draw)"};
240 cvar_t r_batch_multidraw_mintriangles = {CVAR_CLIENT | CVAR_SAVE, "r_batch_multidraw_mintriangles", "0", "minimum number of triangles to activate multidraw path (copying small groups of triangles may be faster)"};
241 cvar_t r_batch_debugdynamicvertexpath = {CVAR_CLIENT | CVAR_SAVE, "r_batch_debugdynamicvertexpath", "0", "force the dynamic batching code path for debugging purposes"};
242 cvar_t r_batch_dynamicbuffer = {CVAR_CLIENT | CVAR_SAVE, "r_batch_dynamicbuffer", "0", "use vertex/index buffers for drawing dynamic and copytriangles batches"};
243
244 cvar_t r_glsl_saturation = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
245 cvar_t r_glsl_saturation_redcompensate = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_saturation_redcompensate", "0", "a 'vampire sight' addition to desaturation effect, does compensation for red color, r_glsl_restart is required"};
246
247 cvar_t r_glsl_vertextextureblend_usebothalphas = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_vertextextureblend_usebothalphas", "0", "use both alpha layers on vertex blended surfaces, each alpha layer sets amount of 'blend leak' on another layer, requires mod_q3shader_force_terrain_alphaflag on."};
248
249 cvar_t r_framedatasize = {CVAR_CLIENT | CVAR_SAVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"};
250 cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
251 {
252         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"},
253         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"},
254         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"},
255         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
256 };
257
258 extern cvar_t v_glslgamma_2d;
259
260 extern qboolean v_flipped_state;
261
262 r_framebufferstate_t r_fb;
263
264 /// shadow volume bsp struct with automatically growing nodes buffer
265 svbsp_t r_svbsp;
266
267 int r_uniformbufferalignment = 32; // dynamically updated to match GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
268
269 rtexture_t *r_texture_blanknormalmap;
270 rtexture_t *r_texture_white;
271 rtexture_t *r_texture_grey128;
272 rtexture_t *r_texture_black;
273 rtexture_t *r_texture_notexture;
274 rtexture_t *r_texture_whitecube;
275 rtexture_t *r_texture_normalizationcube;
276 rtexture_t *r_texture_fogattenuation;
277 rtexture_t *r_texture_fogheighttexture;
278 rtexture_t *r_texture_gammaramps;
279 unsigned int r_texture_gammaramps_serial;
280 //rtexture_t *r_texture_fogintensity;
281 rtexture_t *r_texture_reflectcube;
282
283 // TODO: hash lookups?
284 typedef struct cubemapinfo_s
285 {
286         char basename[64];
287         rtexture_t *texture;
288 }
289 cubemapinfo_t;
290
291 int r_texture_numcubemaps;
292 cubemapinfo_t *r_texture_cubemaps[MAX_CUBEMAPS];
293
294 unsigned int r_queries[MAX_OCCLUSION_QUERIES];
295 unsigned int r_numqueries;
296 unsigned int r_maxqueries;
297
298 typedef struct r_qwskincache_s
299 {
300         char name[MAX_QPATH];
301         skinframe_t *skinframe;
302 }
303 r_qwskincache_t;
304
305 static r_qwskincache_t *r_qwskincache;
306 static int r_qwskincache_size;
307
308 /// vertex coordinates for a quad that covers the screen exactly
309 extern const float r_screenvertex3f[12];
310 const float r_screenvertex3f[12] =
311 {
312         0, 0, 0,
313         1, 0, 0,
314         1, 1, 0,
315         0, 1, 0
316 };
317
318 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
319 {
320         int i;
321         for (i = 0;i < verts;i++)
322         {
323                 out[0] = in[0] * r;
324                 out[1] = in[1] * g;
325                 out[2] = in[2] * b;
326                 out[3] = in[3];
327                 in += 4;
328                 out += 4;
329         }
330 }
331
332 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
333 {
334         int i;
335         for (i = 0;i < verts;i++)
336         {
337                 out[0] = r;
338                 out[1] = g;
339                 out[2] = b;
340                 out[3] = a;
341                 out += 4;
342         }
343 }
344
345 // FIXME: move this to client?
346 void FOG_clear(void)
347 {
348         if (gamemode == GAME_NEHAHRA)
349         {
350                 Cvar_Set(&cvars_all, "gl_fogenable", "0");
351                 Cvar_Set(&cvars_all, "gl_fogdensity", "0.2");
352                 Cvar_Set(&cvars_all, "gl_fogred", "0.3");
353                 Cvar_Set(&cvars_all, "gl_foggreen", "0.3");
354                 Cvar_Set(&cvars_all, "gl_fogblue", "0.3");
355         }
356         r_refdef.fog_density = 0;
357         r_refdef.fog_red = 0;
358         r_refdef.fog_green = 0;
359         r_refdef.fog_blue = 0;
360         r_refdef.fog_alpha = 1;
361         r_refdef.fog_start = 0;
362         r_refdef.fog_end = 16384;
363         r_refdef.fog_height = 1<<30;
364         r_refdef.fog_fadedepth = 128;
365         memset(r_refdef.fog_height_texturename, 0, sizeof(r_refdef.fog_height_texturename));
366 }
367
368 static void R_BuildBlankTextures(void)
369 {
370         unsigned char data[4];
371         data[2] = 128; // normal X
372         data[1] = 128; // normal Y
373         data[0] = 255; // normal Z
374         data[3] = 255; // height
375         r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
376         data[0] = 255;
377         data[1] = 255;
378         data[2] = 255;
379         data[3] = 255;
380         r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
381         data[0] = 128;
382         data[1] = 128;
383         data[2] = 128;
384         data[3] = 255;
385         r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
386         data[0] = 0;
387         data[1] = 0;
388         data[2] = 0;
389         data[3] = 255;
390         r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
391 }
392
393 static void R_BuildNoTexture(void)
394 {
395         int x, y;
396         unsigned char pix[16][16][4];
397         // this makes a light grey/dark grey checkerboard texture
398         for (y = 0;y < 16;y++)
399         {
400                 for (x = 0;x < 16;x++)
401                 {
402                         if ((y < 8) ^ (x < 8))
403                         {
404                                 pix[y][x][0] = 128;
405                                 pix[y][x][1] = 128;
406                                 pix[y][x][2] = 128;
407                                 pix[y][x][3] = 255;
408                         }
409                         else
410                         {
411                                 pix[y][x][0] = 64;
412                                 pix[y][x][1] = 64;
413                                 pix[y][x][2] = 64;
414                                 pix[y][x][3] = 255;
415                         }
416                 }
417         }
418         r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, -1, NULL);
419 }
420
421 static void R_BuildWhiteCube(void)
422 {
423         unsigned char data[6*1*1*4];
424         memset(data, 255, sizeof(data));
425         r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
426 }
427
428 static void R_BuildNormalizationCube(void)
429 {
430         int x, y, side;
431         vec3_t v;
432         vec_t s, t, intensity;
433 #define NORMSIZE 64
434         unsigned char *data;
435         data = (unsigned char *)Mem_Alloc(tempmempool, 6*NORMSIZE*NORMSIZE*4);
436         for (side = 0;side < 6;side++)
437         {
438                 for (y = 0;y < NORMSIZE;y++)
439                 {
440                         for (x = 0;x < NORMSIZE;x++)
441                         {
442                                 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
443                                 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
444                                 switch(side)
445                                 {
446                                 default:
447                                 case 0:
448                                         v[0] = 1;
449                                         v[1] = -t;
450                                         v[2] = -s;
451                                         break;
452                                 case 1:
453                                         v[0] = -1;
454                                         v[1] = -t;
455                                         v[2] = s;
456                                         break;
457                                 case 2:
458                                         v[0] = s;
459                                         v[1] = 1;
460                                         v[2] = t;
461                                         break;
462                                 case 3:
463                                         v[0] = s;
464                                         v[1] = -1;
465                                         v[2] = -t;
466                                         break;
467                                 case 4:
468                                         v[0] = s;
469                                         v[1] = -t;
470                                         v[2] = 1;
471                                         break;
472                                 case 5:
473                                         v[0] = -s;
474                                         v[1] = -t;
475                                         v[2] = -1;
476                                         break;
477                                 }
478                                 intensity = 127.0f / sqrt(DotProduct(v, v));
479                                 data[((side*64+y)*64+x)*4+2] = (unsigned char)(128.0f + intensity * v[0]);
480                                 data[((side*64+y)*64+x)*4+1] = (unsigned char)(128.0f + intensity * v[1]);
481                                 data[((side*64+y)*64+x)*4+0] = (unsigned char)(128.0f + intensity * v[2]);
482                                 data[((side*64+y)*64+x)*4+3] = 255;
483                         }
484                 }
485         }
486         r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
487         Mem_Free(data);
488 }
489
490 static void R_BuildFogTexture(void)
491 {
492         int x, b;
493 #define FOGWIDTH 256
494         unsigned char data1[FOGWIDTH][4];
495         //unsigned char data2[FOGWIDTH][4];
496         double d, r, alpha;
497
498         r_refdef.fogmasktable_start = r_refdef.fog_start;
499         r_refdef.fogmasktable_alpha = r_refdef.fog_alpha;
500         r_refdef.fogmasktable_range = r_refdef.fogrange;
501         r_refdef.fogmasktable_density = r_refdef.fog_density;
502
503         r = r_refdef.fogmasktable_range / FOGMASKTABLEWIDTH;
504         for (x = 0;x < FOGMASKTABLEWIDTH;x++)
505         {
506                 d = (x * r - r_refdef.fogmasktable_start);
507                 if(developer_extra.integer)
508                         Con_DPrintf("%f ", d);
509                 d = max(0, d);
510                 if (r_fog_exp2.integer)
511                         alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d);
512                 else
513                         alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d);
514                 if(developer_extra.integer)
515                         Con_DPrintf(" : %f ", alpha);
516                 alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha;
517                 if(developer_extra.integer)
518                         Con_DPrintf(" = %f\n", alpha);
519                 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
520         }
521
522         for (x = 0;x < FOGWIDTH;x++)
523         {
524                 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
525                 data1[x][0] = b;
526                 data1[x][1] = b;
527                 data1[x][2] = b;
528                 data1[x][3] = 255;
529                 //data2[x][0] = 255 - b;
530                 //data2[x][1] = 255 - b;
531                 //data2[x][2] = 255 - b;
532                 //data2[x][3] = 255;
533         }
534         if (r_texture_fogattenuation)
535         {
536                 R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
537                 //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
538         }
539         else
540         {
541                 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
542                 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
543         }
544 }
545
546 static void R_BuildFogHeightTexture(void)
547 {
548         unsigned char *inpixels;
549         int size;
550         int x;
551         int y;
552         int j;
553         float c[4];
554         float f;
555         inpixels = NULL;
556         strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename));
557         if (r_refdef.fogheighttexturename[0])
558                 inpixels = loadimagepixelsbgra(r_refdef.fogheighttexturename, true, false, false, NULL);
559         if (!inpixels)
560         {
561                 r_refdef.fog_height_tablesize = 0;
562                 if (r_texture_fogheighttexture)
563                         R_FreeTexture(r_texture_fogheighttexture);
564                 r_texture_fogheighttexture = NULL;
565                 if (r_refdef.fog_height_table2d)
566                         Mem_Free(r_refdef.fog_height_table2d);
567                 r_refdef.fog_height_table2d = NULL;
568                 if (r_refdef.fog_height_table1d)
569                         Mem_Free(r_refdef.fog_height_table1d);
570                 r_refdef.fog_height_table1d = NULL;
571                 return;
572         }
573         size = image_width;
574         r_refdef.fog_height_tablesize = size;
575         r_refdef.fog_height_table1d = (unsigned char *)Mem_Alloc(r_main_mempool, size * 4);
576         r_refdef.fog_height_table2d = (unsigned char *)Mem_Alloc(r_main_mempool, size * size * 4);
577         memcpy(r_refdef.fog_height_table1d, inpixels, size * 4);
578         Mem_Free(inpixels);
579         // LadyHavoc: now the magic - what is that table2d for?  it is a cooked
580         // average fog color table accounting for every fog layer between a point
581         // and the camera.  (Note: attenuation is handled separately!)
582         for (y = 0;y < size;y++)
583         {
584                 for (x = 0;x < size;x++)
585                 {
586                         Vector4Clear(c);
587                         f = 0;
588                         if (x < y)
589                         {
590                                 for (j = x;j <= y;j++)
591                                 {
592                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
593                                         f++;
594                                 }
595                         }
596                         else
597                         {
598                                 for (j = x;j >= y;j--)
599                                 {
600                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
601                                         f++;
602                                 }
603                         }
604                         f = 1.0f / f;
605                         r_refdef.fog_height_table2d[(y*size+x)*4+0] = (unsigned char)(c[0] * f);
606                         r_refdef.fog_height_table2d[(y*size+x)*4+1] = (unsigned char)(c[1] * f);
607                         r_refdef.fog_height_table2d[(y*size+x)*4+2] = (unsigned char)(c[2] * f);
608                         r_refdef.fog_height_table2d[(y*size+x)*4+3] = (unsigned char)(c[3] * f);
609                 }
610         }
611         r_texture_fogheighttexture = R_LoadTexture2D(r_main_texturepool, "fogheighttable", size, size, r_refdef.fog_height_table2d, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_CLAMP, -1, NULL);
612 }
613
614 //=======================================================================================================================================================
615
616 static const char *builtinshaderstrings[] =
617 {
618 #include "shader_glsl.h"
619 0
620 };
621
622 //=======================================================================================================================================================
623
624 typedef struct shaderpermutationinfo_s
625 {
626         const char *pretext;
627         const char *name;
628 }
629 shaderpermutationinfo_t;
630
631 typedef struct shadermodeinfo_s
632 {
633         const char *sourcebasename;
634         const char *extension;
635         const char **builtinshaderstrings;
636         const char *pretext;
637         const char *name;
638         char *filename;
639         char *builtinstring;
640         int builtincrc;
641 }
642 shadermodeinfo_t;
643
644 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
645 shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
646 {
647         {"#define USEDIFFUSE\n", " diffuse"},
648         {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
649         {"#define USEVIEWTINT\n", " viewtint"},
650         {"#define USECOLORMAPPING\n", " colormapping"},
651         {"#define USESATURATION\n", " saturation"},
652         {"#define USEFOGINSIDE\n", " foginside"},
653         {"#define USEFOGOUTSIDE\n", " fogoutside"},
654         {"#define USEFOGHEIGHTTEXTURE\n", " fogheighttexture"},
655         {"#define USEFOGALPHAHACK\n", " fogalphahack"},
656         {"#define USEGAMMARAMPS\n", " gammaramps"},
657         {"#define USECUBEFILTER\n", " cubefilter"},
658         {"#define USEGLOW\n", " glow"},
659         {"#define USEBLOOM\n", " bloom"},
660         {"#define USESPECULAR\n", " specular"},
661         {"#define USEPOSTPROCESSING\n", " postprocessing"},
662         {"#define USEREFLECTION\n", " reflection"},
663         {"#define USEOFFSETMAPPING\n", " offsetmapping"},
664         {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
665         {"#define USESHADOWMAP2D\n", " shadowmap2d"},
666         {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm
667         {"#define USESHADOWMAPORTHO\n", " shadowmaportho"},
668         {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
669         {"#define USEALPHAKILL\n", " alphakill"},
670         {"#define USEREFLECTCUBE\n", " reflectcube"},
671         {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"},
672         {"#define USEBOUNCEGRID\n", " bouncegrid"},
673         {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm
674         {"#define USETRIPPY\n", " trippy"},
675         {"#define USEDEPTHRGB\n", " depthrgb"},
676         {"#define USEALPHAGENVERTEX\n", " alphagenvertex"},
677         {"#define USESKELETAL\n", " skeletal"},
678         {"#define USEOCCLUDE\n", " occlude"}
679 };
680
681 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
682 shadermodeinfo_t shadermodeinfo[SHADERLANGUAGE_COUNT][SHADERMODE_COUNT] =
683 {
684         // SHADERLANGUAGE_GLSL
685         {
686                 {"combined", "glsl", builtinshaderstrings, "#define MODE_GENERIC\n", " generic"},
687                 {"combined", "glsl", builtinshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
688                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
689                 {"combined", "glsl", builtinshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
690                 {"combined", "glsl", builtinshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
691                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
692                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
693                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
694                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
695                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
696                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
697                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
698                 {"combined", "glsl", builtinshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
699                 {"combined", "glsl", builtinshaderstrings, "#define MODE_WATER\n", " water"},
700                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
701                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
702         },
703 };
704
705 struct r_glsl_permutation_s;
706 typedef struct r_glsl_permutation_s
707 {
708         /// hash lookup data
709         struct r_glsl_permutation_s *hashnext;
710         unsigned int mode;
711         dpuint64 permutation;
712
713         /// indicates if we have tried compiling this permutation already
714         qboolean compiled;
715         /// 0 if compilation failed
716         int program;
717         // texture units assigned to each detected uniform
718         int tex_Texture_First;
719         int tex_Texture_Second;
720         int tex_Texture_GammaRamps;
721         int tex_Texture_Normal;
722         int tex_Texture_Color;
723         int tex_Texture_Gloss;
724         int tex_Texture_Glow;
725         int tex_Texture_SecondaryNormal;
726         int tex_Texture_SecondaryColor;
727         int tex_Texture_SecondaryGloss;
728         int tex_Texture_SecondaryGlow;
729         int tex_Texture_Pants;
730         int tex_Texture_Shirt;
731         int tex_Texture_FogHeightTexture;
732         int tex_Texture_FogMask;
733         int tex_Texture_Lightmap;
734         int tex_Texture_Deluxemap;
735         int tex_Texture_Attenuation;
736         int tex_Texture_Cube;
737         int tex_Texture_Refraction;
738         int tex_Texture_Reflection;
739         int tex_Texture_ShadowMap2D;
740         int tex_Texture_CubeProjection;
741         int tex_Texture_ScreenNormalMap;
742         int tex_Texture_ScreenDiffuse;
743         int tex_Texture_ScreenSpecular;
744         int tex_Texture_ReflectMask;
745         int tex_Texture_ReflectCube;
746         int tex_Texture_BounceGrid;
747         /// locations of detected uniforms in program object, or -1 if not found
748         int loc_Texture_First;
749         int loc_Texture_Second;
750         int loc_Texture_GammaRamps;
751         int loc_Texture_Normal;
752         int loc_Texture_Color;
753         int loc_Texture_Gloss;
754         int loc_Texture_Glow;
755         int loc_Texture_SecondaryNormal;
756         int loc_Texture_SecondaryColor;
757         int loc_Texture_SecondaryGloss;
758         int loc_Texture_SecondaryGlow;
759         int loc_Texture_Pants;
760         int loc_Texture_Shirt;
761         int loc_Texture_FogHeightTexture;
762         int loc_Texture_FogMask;
763         int loc_Texture_Lightmap;
764         int loc_Texture_Deluxemap;
765         int loc_Texture_Attenuation;
766         int loc_Texture_Cube;
767         int loc_Texture_Refraction;
768         int loc_Texture_Reflection;
769         int loc_Texture_ShadowMap2D;
770         int loc_Texture_CubeProjection;
771         int loc_Texture_ScreenNormalMap;
772         int loc_Texture_ScreenDiffuse;
773         int loc_Texture_ScreenSpecular;
774         int loc_Texture_ReflectMask;
775         int loc_Texture_ReflectCube;
776         int loc_Texture_BounceGrid;
777         int loc_Alpha;
778         int loc_BloomBlur_Parameters;
779         int loc_ClientTime;
780         int loc_Color_Ambient;
781         int loc_Color_Diffuse;
782         int loc_Color_Specular;
783         int loc_Color_Glow;
784         int loc_Color_Pants;
785         int loc_Color_Shirt;
786         int loc_DeferredColor_Ambient;
787         int loc_DeferredColor_Diffuse;
788         int loc_DeferredColor_Specular;
789         int loc_DeferredMod_Diffuse;
790         int loc_DeferredMod_Specular;
791         int loc_DistortScaleRefractReflect;
792         int loc_EyePosition;
793         int loc_FogColor;
794         int loc_FogHeightFade;
795         int loc_FogPlane;
796         int loc_FogPlaneViewDist;
797         int loc_FogRangeRecip;
798         int loc_LightColor;
799         int loc_LightDir;
800         int loc_LightPosition;
801         int loc_OffsetMapping_ScaleSteps;
802         int loc_OffsetMapping_LodDistance;
803         int loc_OffsetMapping_Bias;
804         int loc_PixelSize;
805         int loc_ReflectColor;
806         int loc_ReflectFactor;
807         int loc_ReflectOffset;
808         int loc_RefractColor;
809         int loc_Saturation;
810         int loc_ScreenCenterRefractReflect;
811         int loc_ScreenScaleRefractReflect;
812         int loc_ScreenToDepth;
813         int loc_ShadowMap_Parameters;
814         int loc_ShadowMap_TextureScale;
815         int loc_SpecularPower;
816         int loc_Skeletal_Transform12;
817         int loc_UserVec1;
818         int loc_UserVec2;
819         int loc_UserVec3;
820         int loc_UserVec4;
821         int loc_ColorFringe;
822         int loc_ViewTintColor;
823         int loc_ViewToLight;
824         int loc_ModelToLight;
825         int loc_TexMatrix;
826         int loc_BackgroundTexMatrix;
827         int loc_ModelViewProjectionMatrix;
828         int loc_ModelViewMatrix;
829         int loc_PixelToScreenTexCoord;
830         int loc_ModelToReflectCube;
831         int loc_ShadowMapMatrix;
832         int loc_BloomColorSubtract;
833         int loc_NormalmapScrollBlend;
834         int loc_BounceGridMatrix;
835         int loc_BounceGridIntensity;
836         /// uniform block bindings
837         int ubibind_Skeletal_Transform12_UniformBlock;
838         /// uniform block indices
839         int ubiloc_Skeletal_Transform12_UniformBlock;
840 }
841 r_glsl_permutation_t;
842
843 #define SHADERPERMUTATION_HASHSIZE 256
844
845
846 // non-degradable "lightweight" shader parameters to keep the permutations simpler
847 // these can NOT degrade! only use for simple stuff
848 enum
849 {
850         SHADERSTATICPARM_SATURATION_REDCOMPENSATE = 0, ///< red compensation filter for saturation
851         SHADERSTATICPARM_EXACTSPECULARMATH = 1, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
852         SHADERSTATICPARM_POSTPROCESS_USERVEC1 = 2, ///< postprocess uservec1 is enabled
853         SHADERSTATICPARM_POSTPROCESS_USERVEC2 = 3, ///< postprocess uservec2 is enabled
854         SHADERSTATICPARM_POSTPROCESS_USERVEC3 = 4, ///< postprocess uservec3 is enabled
855         SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5,  ///< postprocess uservec4 is enabled
856         SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending
857         SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7,  ///< LOD for offsetmapping
858         SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1
859         SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2
860         SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
861         SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
862         SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
863         SHADERSTATICPARM_FXAA = 13 ///< fast approximate anti aliasing
864 };
865 #define SHADERSTATICPARMS_COUNT 14
866
867 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
868 static int shaderstaticparms_count = 0;
869
870 static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0};
871 #define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F))
872
873 extern qboolean r_shadow_shadowmapsampler;
874 extern int r_shadow_shadowmappcf;
875 qboolean R_CompileShader_CheckStaticParms(void)
876 {
877         static int r_compileshader_staticparms_save[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5];
878         memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
879         memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
880
881         // detect all
882         if (r_glsl_saturation_redcompensate.integer)
883                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SATURATION_REDCOMPENSATE);
884         if (r_glsl_vertextextureblend_usebothalphas.integer)
885                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS);
886         if (r_shadow_glossexact.integer)
887                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_EXACTSPECULARMATH);
888         if (r_glsl_postprocess.integer)
889         {
890                 if (r_glsl_postprocess_uservec1_enable.integer)
891                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC1);
892                 if (r_glsl_postprocess_uservec2_enable.integer)
893                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC2);
894                 if (r_glsl_postprocess_uservec3_enable.integer)
895                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC3);
896                 if (r_glsl_postprocess_uservec4_enable.integer)
897                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
898         }
899         if (r_fxaa.integer)
900                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_FXAA);
901         if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
902                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
903
904         if (r_shadow_shadowmapsampler)
905                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER);
906         if (r_shadow_shadowmappcf > 1)
907                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2);
908         else if (r_shadow_shadowmappcf)
909                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1);
910         if (r_celshading.integer)
911                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING);
912         if (r_celoutlines.integer)
913                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES);
914
915         return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
916 }
917
918 #define R_COMPILESHADER_STATICPARM_EMIT(p, n) \
919         if(r_compileshader_staticparms[(p) >> 5] & (1 << ((p) & 0x1F))) \
920                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \
921         else \
922                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n"
923 static void R_CompileShader_AddStaticParms(unsigned int mode, dpuint64 permutation)
924 {
925         shaderstaticparms_count = 0;
926
927         // emit all
928         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SATURATION_REDCOMPENSATE, "SATURATION_REDCOMPENSATE");
929         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_EXACTSPECULARMATH, "USEEXACTSPECULARMATH");
930         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC1, "USERVEC1");
931         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC2, "USERVEC2");
932         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC3, "USERVEC3");
933         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4");
934         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS");
935         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD");
936         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1");
937         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2");
938         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
939         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
940         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
941         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
942 }
943
944 /// information about each possible shader permutation
945 r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
946 /// currently selected permutation
947 r_glsl_permutation_t *r_glsl_permutation;
948 /// storage for permutations linked in the hash table
949 memexpandablearray_t r_glsl_permutationarray;
950
951 static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, dpuint64 permutation)
952 {
953         //unsigned int hashdepth = 0;
954         unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
955         r_glsl_permutation_t *p;
956         for (p = r_glsl_permutationhash[mode][hashindex];p;p = p->hashnext)
957         {
958                 if (p->mode == mode && p->permutation == permutation)
959                 {
960                         //if (hashdepth > 10)
961                         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
962                         return p;
963                 }
964                 //hashdepth++;
965         }
966         p = (r_glsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_glsl_permutationarray);
967         p->mode = mode;
968         p->permutation = permutation;
969         p->hashnext = r_glsl_permutationhash[mode][hashindex];
970         r_glsl_permutationhash[mode][hashindex] = p;
971         //if (hashdepth > 10)
972         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
973         return p;
974 }
975
976 static char *R_ShaderStrCat(const char **strings)
977 {
978         char *string, *s;
979         const char **p = strings;
980         const char *t;
981         size_t len = 0;
982         for (p = strings;(t = *p);p++)
983                 len += strlen(t);
984         len++;
985         s = string = (char *)Mem_Alloc(r_main_mempool, len);
986         len = 0;
987         for (p = strings;(t = *p);p++)
988         {
989                 len = strlen(t);
990                 memcpy(s, t, len);
991                 s += len;
992         }
993         *s = 0;
994         return string;
995 }
996
997 static char *R_ShaderStrCat(const char **strings);
998 static void R_InitShaderModeInfo(void)
999 {
1000         int i, language;
1001         shadermodeinfo_t *modeinfo;
1002         // we have a bunch of things to compute that weren't calculated at engine compile time - all filenames should have a crc of the builtin strings to prevent accidental overrides (any customization must be updated to match engine)
1003         for (language = 0; language < SHADERLANGUAGE_COUNT; language++)
1004         {
1005                 for (i = 0; i < SHADERMODE_COUNT; i++)
1006                 {
1007                         char filename[MAX_QPATH];
1008                         modeinfo = &shadermodeinfo[language][i];
1009                         modeinfo->builtinstring = R_ShaderStrCat(modeinfo->builtinshaderstrings);
1010                         modeinfo->builtincrc = CRC_Block((const unsigned char *)modeinfo->builtinstring, strlen(modeinfo->builtinstring));
1011                         dpsnprintf(filename, sizeof(filename), "%s/%s_crc%i.%s", modeinfo->extension, modeinfo->sourcebasename, modeinfo->builtincrc, modeinfo->extension);
1012                         modeinfo->filename = Mem_strdup(r_main_mempool, filename);
1013                 }
1014         }
1015 }
1016
1017 static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qboolean printfromdisknotice, qboolean builtinonly)
1018 {
1019         char *shaderstring;
1020         // if the mode has no filename we have to return the builtin string
1021         if (builtinonly || !modeinfo->filename)
1022                 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1023         // note that FS_LoadFile appends a 0 byte to make it a valid string
1024         shaderstring = (char *)FS_LoadFile(modeinfo->filename, r_main_mempool, false, NULL);
1025         if (shaderstring)
1026         {
1027                 if (printfromdisknotice)
1028                         Con_DPrintf("Loading shaders from file %s...\n", modeinfo->filename);
1029                 return shaderstring;
1030         }
1031         // fall back to builtinstring
1032         return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1033 }
1034
1035 static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, dpuint64 permutation)
1036 {
1037         int i;
1038         int ubibind;
1039         int sampler;
1040         shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode];
1041         char *sourcestring;
1042         char permutationname[256];
1043         int vertstrings_count = 0;
1044         int geomstrings_count = 0;
1045         int fragstrings_count = 0;
1046         const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1047         const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1048         const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1049
1050         if (p->compiled)
1051                 return;
1052         p->compiled = true;
1053         p->program = 0;
1054
1055         permutationname[0] = 0;
1056         sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false);
1057
1058         strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
1059
1060         // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object)
1061         if(vid.support.glshaderversion >= 140)
1062         {
1063                 vertstrings_list[vertstrings_count++] = "#version 140\n";
1064                 geomstrings_list[geomstrings_count++] = "#version 140\n";
1065                 fragstrings_list[fragstrings_count++] = "#version 140\n";
1066                 vertstrings_list[vertstrings_count++] = "#define GLSL140\n";
1067                 geomstrings_list[geomstrings_count++] = "#define GLSL140\n";
1068                 fragstrings_list[fragstrings_count++] = "#define GLSL140\n";
1069         }
1070         // if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad)
1071         else if(vid.support.glshaderversion >= 130)
1072         {
1073                 vertstrings_list[vertstrings_count++] = "#version 130\n";
1074                 geomstrings_list[geomstrings_count++] = "#version 130\n";
1075                 fragstrings_list[fragstrings_count++] = "#version 130\n";
1076                 vertstrings_list[vertstrings_count++] = "#define GLSL130\n";
1077                 geomstrings_list[geomstrings_count++] = "#define GLSL130\n";
1078                 fragstrings_list[fragstrings_count++] = "#define GLSL130\n";
1079         }
1080         // if we can do #version 120, we should (this adds the invariant keyword)
1081         else if(vid.support.glshaderversion >= 120)
1082         {
1083                 vertstrings_list[vertstrings_count++] = "#version 120\n";
1084                 geomstrings_list[geomstrings_count++] = "#version 120\n";
1085                 fragstrings_list[fragstrings_count++] = "#version 120\n";
1086                 vertstrings_list[vertstrings_count++] = "#define GLSL120\n";
1087                 geomstrings_list[geomstrings_count++] = "#define GLSL120\n";
1088                 fragstrings_list[fragstrings_count++] = "#define GLSL120\n";
1089         }
1090         // GLES also adds several things from GLSL120
1091         switch(vid.renderpath)
1092         {
1093         case RENDERPATH_GLES2:
1094                 vertstrings_list[vertstrings_count++] = "#define GLES\n";
1095                 geomstrings_list[geomstrings_count++] = "#define GLES\n";
1096                 fragstrings_list[fragstrings_count++] = "#define GLES\n";
1097                 break;
1098         default:
1099                 break;
1100         }
1101
1102         // the first pretext is which type of shader to compile as
1103         // (later these will all be bound together as a program object)
1104         vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
1105         geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
1106         fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
1107
1108         // the second pretext is the mode (for example a light source)
1109         vertstrings_list[vertstrings_count++] = modeinfo->pretext;
1110         geomstrings_list[geomstrings_count++] = modeinfo->pretext;
1111         fragstrings_list[fragstrings_count++] = modeinfo->pretext;
1112         strlcat(permutationname, modeinfo->name, sizeof(permutationname));
1113
1114         // now add all the permutation pretexts
1115         for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1116         {
1117                 if (permutation & (1ll<<i))
1118                 {
1119                         vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
1120                         geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
1121                         fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
1122                         strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
1123                 }
1124                 else
1125                 {
1126                         // keep line numbers correct
1127                         vertstrings_list[vertstrings_count++] = "\n";
1128                         geomstrings_list[geomstrings_count++] = "\n";
1129                         fragstrings_list[fragstrings_count++] = "\n";
1130                 }
1131         }
1132
1133         // add static parms
1134         R_CompileShader_AddStaticParms(mode, permutation);
1135         memcpy((char *)(vertstrings_list + vertstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1136         vertstrings_count += shaderstaticparms_count;
1137         memcpy((char *)(geomstrings_list + geomstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1138         geomstrings_count += shaderstaticparms_count;
1139         memcpy((char *)(fragstrings_list + fragstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1140         fragstrings_count += shaderstaticparms_count;
1141
1142         // now append the shader text itself
1143         vertstrings_list[vertstrings_count++] = sourcestring;
1144         geomstrings_list[geomstrings_count++] = sourcestring;
1145         fragstrings_list[fragstrings_count++] = sourcestring;
1146
1147         // we don't currently use geometry shaders for anything, so just empty the list
1148         geomstrings_count = 0;
1149
1150         // compile the shader program
1151         if (vertstrings_count + geomstrings_count + fragstrings_count)
1152                 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1153         if (p->program)
1154         {
1155                 CHECKGLERROR
1156                 qglUseProgram(p->program);CHECKGLERROR
1157                 // look up all the uniform variable names we care about, so we don't
1158                 // have to look them up every time we set them
1159
1160 #if 0
1161                 // debugging aid
1162                 {
1163                         GLint activeuniformindex = 0;
1164                         GLint numactiveuniforms = 0;
1165                         char uniformname[128];
1166                         GLsizei uniformnamelength = 0;
1167                         GLint uniformsize = 0;
1168                         GLenum uniformtype = 0;
1169                         memset(uniformname, 0, sizeof(uniformname));
1170                         qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms);
1171                         Con_Printf("Shader has %i uniforms\n", numactiveuniforms);
1172                         for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++)
1173                         {
1174                                 qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname);
1175                                 Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype);
1176                         }
1177                 }
1178 #endif
1179
1180                 p->loc_Texture_First              = qglGetUniformLocation(p->program, "Texture_First");
1181                 p->loc_Texture_Second             = qglGetUniformLocation(p->program, "Texture_Second");
1182                 p->loc_Texture_GammaRamps         = qglGetUniformLocation(p->program, "Texture_GammaRamps");
1183                 p->loc_Texture_Normal             = qglGetUniformLocation(p->program, "Texture_Normal");
1184                 p->loc_Texture_Color              = qglGetUniformLocation(p->program, "Texture_Color");
1185                 p->loc_Texture_Gloss              = qglGetUniformLocation(p->program, "Texture_Gloss");
1186                 p->loc_Texture_Glow               = qglGetUniformLocation(p->program, "Texture_Glow");
1187                 p->loc_Texture_SecondaryNormal    = qglGetUniformLocation(p->program, "Texture_SecondaryNormal");
1188                 p->loc_Texture_SecondaryColor     = qglGetUniformLocation(p->program, "Texture_SecondaryColor");
1189                 p->loc_Texture_SecondaryGloss     = qglGetUniformLocation(p->program, "Texture_SecondaryGloss");
1190                 p->loc_Texture_SecondaryGlow      = qglGetUniformLocation(p->program, "Texture_SecondaryGlow");
1191                 p->loc_Texture_Pants              = qglGetUniformLocation(p->program, "Texture_Pants");
1192                 p->loc_Texture_Shirt              = qglGetUniformLocation(p->program, "Texture_Shirt");
1193                 p->loc_Texture_FogHeightTexture   = qglGetUniformLocation(p->program, "Texture_FogHeightTexture");
1194                 p->loc_Texture_FogMask            = qglGetUniformLocation(p->program, "Texture_FogMask");
1195                 p->loc_Texture_Lightmap           = qglGetUniformLocation(p->program, "Texture_Lightmap");
1196                 p->loc_Texture_Deluxemap          = qglGetUniformLocation(p->program, "Texture_Deluxemap");
1197                 p->loc_Texture_Attenuation        = qglGetUniformLocation(p->program, "Texture_Attenuation");
1198                 p->loc_Texture_Cube               = qglGetUniformLocation(p->program, "Texture_Cube");
1199                 p->loc_Texture_Refraction         = qglGetUniformLocation(p->program, "Texture_Refraction");
1200                 p->loc_Texture_Reflection         = qglGetUniformLocation(p->program, "Texture_Reflection");
1201                 p->loc_Texture_ShadowMap2D        = qglGetUniformLocation(p->program, "Texture_ShadowMap2D");
1202                 p->loc_Texture_CubeProjection     = qglGetUniformLocation(p->program, "Texture_CubeProjection");
1203                 p->loc_Texture_ScreenNormalMap    = qglGetUniformLocation(p->program, "Texture_ScreenNormalMap");
1204                 p->loc_Texture_ScreenDiffuse      = qglGetUniformLocation(p->program, "Texture_ScreenDiffuse");
1205                 p->loc_Texture_ScreenSpecular     = qglGetUniformLocation(p->program, "Texture_ScreenSpecular");
1206                 p->loc_Texture_ReflectMask        = qglGetUniformLocation(p->program, "Texture_ReflectMask");
1207                 p->loc_Texture_ReflectCube        = qglGetUniformLocation(p->program, "Texture_ReflectCube");
1208                 p->loc_Texture_BounceGrid         = qglGetUniformLocation(p->program, "Texture_BounceGrid");
1209                 p->loc_Alpha                      = qglGetUniformLocation(p->program, "Alpha");
1210                 p->loc_BloomBlur_Parameters       = qglGetUniformLocation(p->program, "BloomBlur_Parameters");
1211                 p->loc_ClientTime                 = qglGetUniformLocation(p->program, "ClientTime");
1212                 p->loc_Color_Ambient              = qglGetUniformLocation(p->program, "Color_Ambient");
1213                 p->loc_Color_Diffuse              = qglGetUniformLocation(p->program, "Color_Diffuse");
1214                 p->loc_Color_Specular             = qglGetUniformLocation(p->program, "Color_Specular");
1215                 p->loc_Color_Glow                 = qglGetUniformLocation(p->program, "Color_Glow");
1216                 p->loc_Color_Pants                = qglGetUniformLocation(p->program, "Color_Pants");
1217                 p->loc_Color_Shirt                = qglGetUniformLocation(p->program, "Color_Shirt");
1218                 p->loc_DeferredColor_Ambient      = qglGetUniformLocation(p->program, "DeferredColor_Ambient");
1219                 p->loc_DeferredColor_Diffuse      = qglGetUniformLocation(p->program, "DeferredColor_Diffuse");
1220                 p->loc_DeferredColor_Specular     = qglGetUniformLocation(p->program, "DeferredColor_Specular");
1221                 p->loc_DeferredMod_Diffuse        = qglGetUniformLocation(p->program, "DeferredMod_Diffuse");
1222                 p->loc_DeferredMod_Specular       = qglGetUniformLocation(p->program, "DeferredMod_Specular");
1223                 p->loc_DistortScaleRefractReflect = qglGetUniformLocation(p->program, "DistortScaleRefractReflect");
1224                 p->loc_EyePosition                = qglGetUniformLocation(p->program, "EyePosition");
1225                 p->loc_FogColor                   = qglGetUniformLocation(p->program, "FogColor");
1226                 p->loc_FogHeightFade              = qglGetUniformLocation(p->program, "FogHeightFade");
1227                 p->loc_FogPlane                   = qglGetUniformLocation(p->program, "FogPlane");
1228                 p->loc_FogPlaneViewDist           = qglGetUniformLocation(p->program, "FogPlaneViewDist");
1229                 p->loc_FogRangeRecip              = qglGetUniformLocation(p->program, "FogRangeRecip");
1230                 p->loc_LightColor                 = qglGetUniformLocation(p->program, "LightColor");
1231                 p->loc_LightDir                   = qglGetUniformLocation(p->program, "LightDir");
1232                 p->loc_LightPosition              = qglGetUniformLocation(p->program, "LightPosition");
1233                 p->loc_OffsetMapping_ScaleSteps   = qglGetUniformLocation(p->program, "OffsetMapping_ScaleSteps");
1234                 p->loc_OffsetMapping_LodDistance  = qglGetUniformLocation(p->program, "OffsetMapping_LodDistance");
1235                 p->loc_OffsetMapping_Bias         = qglGetUniformLocation(p->program, "OffsetMapping_Bias");
1236                 p->loc_PixelSize                  = qglGetUniformLocation(p->program, "PixelSize");
1237                 p->loc_ReflectColor               = qglGetUniformLocation(p->program, "ReflectColor");
1238                 p->loc_ReflectFactor              = qglGetUniformLocation(p->program, "ReflectFactor");
1239                 p->loc_ReflectOffset              = qglGetUniformLocation(p->program, "ReflectOffset");
1240                 p->loc_RefractColor               = qglGetUniformLocation(p->program, "RefractColor");
1241                 p->loc_Saturation                 = qglGetUniformLocation(p->program, "Saturation");
1242                 p->loc_ScreenCenterRefractReflect = qglGetUniformLocation(p->program, "ScreenCenterRefractReflect");
1243                 p->loc_ScreenScaleRefractReflect  = qglGetUniformLocation(p->program, "ScreenScaleRefractReflect");
1244                 p->loc_ScreenToDepth              = qglGetUniformLocation(p->program, "ScreenToDepth");
1245                 p->loc_ShadowMap_Parameters       = qglGetUniformLocation(p->program, "ShadowMap_Parameters");
1246                 p->loc_ShadowMap_TextureScale     = qglGetUniformLocation(p->program, "ShadowMap_TextureScale");
1247                 p->loc_SpecularPower              = qglGetUniformLocation(p->program, "SpecularPower");
1248                 p->loc_UserVec1                   = qglGetUniformLocation(p->program, "UserVec1");
1249                 p->loc_UserVec2                   = qglGetUniformLocation(p->program, "UserVec2");
1250                 p->loc_UserVec3                   = qglGetUniformLocation(p->program, "UserVec3");
1251                 p->loc_UserVec4                   = qglGetUniformLocation(p->program, "UserVec4");
1252                 p->loc_ColorFringe                = qglGetUniformLocation(p->program, "ColorFringe");
1253                 p->loc_ViewTintColor              = qglGetUniformLocation(p->program, "ViewTintColor");
1254                 p->loc_ViewToLight                = qglGetUniformLocation(p->program, "ViewToLight");
1255                 p->loc_ModelToLight               = qglGetUniformLocation(p->program, "ModelToLight");
1256                 p->loc_TexMatrix                  = qglGetUniformLocation(p->program, "TexMatrix");
1257                 p->loc_BackgroundTexMatrix        = qglGetUniformLocation(p->program, "BackgroundTexMatrix");
1258                 p->loc_ModelViewMatrix            = qglGetUniformLocation(p->program, "ModelViewMatrix");
1259                 p->loc_ModelViewProjectionMatrix  = qglGetUniformLocation(p->program, "ModelViewProjectionMatrix");
1260                 p->loc_PixelToScreenTexCoord      = qglGetUniformLocation(p->program, "PixelToScreenTexCoord");
1261                 p->loc_ModelToReflectCube         = qglGetUniformLocation(p->program, "ModelToReflectCube");
1262                 p->loc_ShadowMapMatrix            = qglGetUniformLocation(p->program, "ShadowMapMatrix");
1263                 p->loc_BloomColorSubtract         = qglGetUniformLocation(p->program, "BloomColorSubtract");
1264                 p->loc_NormalmapScrollBlend       = qglGetUniformLocation(p->program, "NormalmapScrollBlend");
1265                 p->loc_BounceGridMatrix           = qglGetUniformLocation(p->program, "BounceGridMatrix");
1266                 p->loc_BounceGridIntensity        = qglGetUniformLocation(p->program, "BounceGridIntensity");
1267                 // initialize the samplers to refer to the texture units we use
1268                 p->tex_Texture_First = -1;
1269                 p->tex_Texture_Second = -1;
1270                 p->tex_Texture_GammaRamps = -1;
1271                 p->tex_Texture_Normal = -1;
1272                 p->tex_Texture_Color = -1;
1273                 p->tex_Texture_Gloss = -1;
1274                 p->tex_Texture_Glow = -1;
1275                 p->tex_Texture_SecondaryNormal = -1;
1276                 p->tex_Texture_SecondaryColor = -1;
1277                 p->tex_Texture_SecondaryGloss = -1;
1278                 p->tex_Texture_SecondaryGlow = -1;
1279                 p->tex_Texture_Pants = -1;
1280                 p->tex_Texture_Shirt = -1;
1281                 p->tex_Texture_FogHeightTexture = -1;
1282                 p->tex_Texture_FogMask = -1;
1283                 p->tex_Texture_Lightmap = -1;
1284                 p->tex_Texture_Deluxemap = -1;
1285                 p->tex_Texture_Attenuation = -1;
1286                 p->tex_Texture_Cube = -1;
1287                 p->tex_Texture_Refraction = -1;
1288                 p->tex_Texture_Reflection = -1;
1289                 p->tex_Texture_ShadowMap2D = -1;
1290                 p->tex_Texture_CubeProjection = -1;
1291                 p->tex_Texture_ScreenNormalMap = -1;
1292                 p->tex_Texture_ScreenDiffuse = -1;
1293                 p->tex_Texture_ScreenSpecular = -1;
1294                 p->tex_Texture_ReflectMask = -1;
1295                 p->tex_Texture_ReflectCube = -1;
1296                 p->tex_Texture_BounceGrid = -1;
1297                 // bind the texture samplers in use
1298                 sampler = 0;
1299                 if (p->loc_Texture_First           >= 0) {p->tex_Texture_First            = sampler;qglUniform1i(p->loc_Texture_First           , sampler);sampler++;}
1300                 if (p->loc_Texture_Second          >= 0) {p->tex_Texture_Second           = sampler;qglUniform1i(p->loc_Texture_Second          , sampler);sampler++;}
1301                 if (p->loc_Texture_GammaRamps      >= 0) {p->tex_Texture_GammaRamps       = sampler;qglUniform1i(p->loc_Texture_GammaRamps      , sampler);sampler++;}
1302                 if (p->loc_Texture_Normal          >= 0) {p->tex_Texture_Normal           = sampler;qglUniform1i(p->loc_Texture_Normal          , sampler);sampler++;}
1303                 if (p->loc_Texture_Color           >= 0) {p->tex_Texture_Color            = sampler;qglUniform1i(p->loc_Texture_Color           , sampler);sampler++;}
1304                 if (p->loc_Texture_Gloss           >= 0) {p->tex_Texture_Gloss            = sampler;qglUniform1i(p->loc_Texture_Gloss           , sampler);sampler++;}
1305                 if (p->loc_Texture_Glow            >= 0) {p->tex_Texture_Glow             = sampler;qglUniform1i(p->loc_Texture_Glow            , sampler);sampler++;}
1306                 if (p->loc_Texture_SecondaryNormal >= 0) {p->tex_Texture_SecondaryNormal  = sampler;qglUniform1i(p->loc_Texture_SecondaryNormal , sampler);sampler++;}
1307                 if (p->loc_Texture_SecondaryColor  >= 0) {p->tex_Texture_SecondaryColor   = sampler;qglUniform1i(p->loc_Texture_SecondaryColor  , sampler);sampler++;}
1308                 if (p->loc_Texture_SecondaryGloss  >= 0) {p->tex_Texture_SecondaryGloss   = sampler;qglUniform1i(p->loc_Texture_SecondaryGloss  , sampler);sampler++;}
1309                 if (p->loc_Texture_SecondaryGlow   >= 0) {p->tex_Texture_SecondaryGlow    = sampler;qglUniform1i(p->loc_Texture_SecondaryGlow   , sampler);sampler++;}
1310                 if (p->loc_Texture_Pants           >= 0) {p->tex_Texture_Pants            = sampler;qglUniform1i(p->loc_Texture_Pants           , sampler);sampler++;}
1311                 if (p->loc_Texture_Shirt           >= 0) {p->tex_Texture_Shirt            = sampler;qglUniform1i(p->loc_Texture_Shirt           , sampler);sampler++;}
1312                 if (p->loc_Texture_FogHeightTexture>= 0) {p->tex_Texture_FogHeightTexture = sampler;qglUniform1i(p->loc_Texture_FogHeightTexture, sampler);sampler++;}
1313                 if (p->loc_Texture_FogMask         >= 0) {p->tex_Texture_FogMask          = sampler;qglUniform1i(p->loc_Texture_FogMask         , sampler);sampler++;}
1314                 if (p->loc_Texture_Lightmap        >= 0) {p->tex_Texture_Lightmap         = sampler;qglUniform1i(p->loc_Texture_Lightmap        , sampler);sampler++;}
1315                 if (p->loc_Texture_Deluxemap       >= 0) {p->tex_Texture_Deluxemap        = sampler;qglUniform1i(p->loc_Texture_Deluxemap       , sampler);sampler++;}
1316                 if (p->loc_Texture_Attenuation     >= 0) {p->tex_Texture_Attenuation      = sampler;qglUniform1i(p->loc_Texture_Attenuation     , sampler);sampler++;}
1317                 if (p->loc_Texture_Cube            >= 0) {p->tex_Texture_Cube             = sampler;qglUniform1i(p->loc_Texture_Cube            , sampler);sampler++;}
1318                 if (p->loc_Texture_Refraction      >= 0) {p->tex_Texture_Refraction       = sampler;qglUniform1i(p->loc_Texture_Refraction      , sampler);sampler++;}
1319                 if (p->loc_Texture_Reflection      >= 0) {p->tex_Texture_Reflection       = sampler;qglUniform1i(p->loc_Texture_Reflection      , sampler);sampler++;}
1320                 if (p->loc_Texture_ShadowMap2D     >= 0) {p->tex_Texture_ShadowMap2D      = sampler;qglUniform1i(p->loc_Texture_ShadowMap2D     , sampler);sampler++;}
1321                 if (p->loc_Texture_CubeProjection  >= 0) {p->tex_Texture_CubeProjection   = sampler;qglUniform1i(p->loc_Texture_CubeProjection  , sampler);sampler++;}
1322                 if (p->loc_Texture_ScreenNormalMap >= 0) {p->tex_Texture_ScreenNormalMap  = sampler;qglUniform1i(p->loc_Texture_ScreenNormalMap , sampler);sampler++;}
1323                 if (p->loc_Texture_ScreenDiffuse   >= 0) {p->tex_Texture_ScreenDiffuse    = sampler;qglUniform1i(p->loc_Texture_ScreenDiffuse   , sampler);sampler++;}
1324                 if (p->loc_Texture_ScreenSpecular  >= 0) {p->tex_Texture_ScreenSpecular   = sampler;qglUniform1i(p->loc_Texture_ScreenSpecular  , sampler);sampler++;}
1325                 if (p->loc_Texture_ReflectMask     >= 0) {p->tex_Texture_ReflectMask      = sampler;qglUniform1i(p->loc_Texture_ReflectMask     , sampler);sampler++;}
1326                 if (p->loc_Texture_ReflectCube     >= 0) {p->tex_Texture_ReflectCube      = sampler;qglUniform1i(p->loc_Texture_ReflectCube     , sampler);sampler++;}
1327                 if (p->loc_Texture_BounceGrid      >= 0) {p->tex_Texture_BounceGrid       = sampler;qglUniform1i(p->loc_Texture_BounceGrid      , sampler);sampler++;}
1328                 // get the uniform block indices so we can bind them
1329                 p->ubiloc_Skeletal_Transform12_UniformBlock = -1;
1330 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1331                 p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
1332 #endif
1333                 // clear the uniform block bindings
1334                 p->ubibind_Skeletal_Transform12_UniformBlock = -1;
1335                 // bind the uniform blocks in use
1336                 ubibind = 0;
1337 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1338                 if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;}
1339 #endif
1340                 // we're done compiling and setting up the shader, at least until it is used
1341                 CHECKGLERROR
1342                 Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler);
1343         }
1344         else
1345                 Con_Printf("^1GLSL shader %s failed!  some features may not work properly.\n", permutationname);
1346
1347         // free the strings
1348         if (sourcestring)
1349                 Mem_Free(sourcestring);
1350 }
1351
1352 static void R_SetupShader_SetPermutationGLSL(unsigned int mode, dpuint64 permutation)
1353 {
1354         r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation);
1355         if (r_glsl_permutation != perm)
1356         {
1357                 r_glsl_permutation = perm;
1358                 if (!r_glsl_permutation->program)
1359                 {
1360                         if (!r_glsl_permutation->compiled)
1361                         {
1362                                 Con_DPrintf("Compiling shader mode %u permutation %llx\n", mode, permutation);
1363                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1364                         }
1365                         if (!r_glsl_permutation->program)
1366                         {
1367                                 // remove features until we find a valid permutation
1368                                 int i;
1369                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1370                                 {
1371                                         // reduce i more quickly whenever it would not remove any bits
1372                                         dpuint64 j = 1ll<<(SHADERPERMUTATION_COUNT-1-i);
1373                                         if (!(permutation & j))
1374                                                 continue;
1375                                         permutation -= j;
1376                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1377                                         if (!r_glsl_permutation->compiled)
1378                                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1379                                         if (r_glsl_permutation->program)
1380                                                 break;
1381                                 }
1382                                 if (i >= SHADERPERMUTATION_COUNT)
1383                                 {
1384                                         //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext);
1385                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1386                                         qglUseProgram(0);CHECKGLERROR
1387                                         return; // no bit left to clear, entire mode is broken
1388                                 }
1389                         }
1390                 }
1391                 CHECKGLERROR
1392                 qglUseProgram(r_glsl_permutation->program);CHECKGLERROR
1393         }
1394         if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
1395         if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
1396         if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time);
1397         CHECKGLERROR
1398 }
1399
1400 void R_GLSL_Restart_f(cmd_state_t *cmd)
1401 {
1402         unsigned int i, limit;
1403         switch(vid.renderpath)
1404         {
1405         case RENDERPATH_GL32:
1406         case RENDERPATH_GLES2:
1407                 {
1408                         r_glsl_permutation_t *p;
1409                         r_glsl_permutation = NULL;
1410                         limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
1411                         for (i = 0;i < limit;i++)
1412                         {
1413                                 if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
1414                                 {
1415                                         GL_Backend_FreeProgram(p->program);
1416                                         Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
1417                                 }
1418                         }
1419                         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
1420                 }
1421                 break;
1422         }
1423 }
1424
1425 static void R_GLSL_DumpShader_f(cmd_state_t *cmd)
1426 {
1427         int i, language, mode, dupe;
1428         char *text;
1429         shadermodeinfo_t *modeinfo;
1430         qfile_t *file;
1431
1432         for (language = 0;language < SHADERLANGUAGE_COUNT;language++)
1433         {
1434                 modeinfo = shadermodeinfo[language];
1435                 for (mode = 0;mode < SHADERMODE_COUNT;mode++)
1436                 {
1437                         // don't dump the same file multiple times (most or all shaders come from the same file)
1438                         for (dupe = mode - 1;dupe >= 0;dupe--)
1439                                 if (!strcmp(modeinfo[mode].filename, modeinfo[dupe].filename))
1440                                         break;
1441                         if (dupe >= 0)
1442                                 continue;
1443                         text = modeinfo[mode].builtinstring;
1444                         if (!text)
1445                                 continue;
1446                         file = FS_OpenRealFile(modeinfo[mode].filename, "w", false);
1447                         if (file)
1448                         {
1449                                 FS_Print(file, "/* The engine may define the following macros:\n");
1450                                 FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
1451                                 for (i = 0;i < SHADERMODE_COUNT;i++)
1452                                         FS_Print(file, modeinfo[i].pretext);
1453                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1454                                         FS_Print(file, shaderpermutationinfo[i].pretext);
1455                                 FS_Print(file, "*/\n");
1456                                 FS_Print(file, text);
1457                                 FS_Close(file);
1458                                 Con_Printf("%s written\n", modeinfo[mode].filename);
1459                         }
1460                         else
1461                                 Con_Printf("failed to write to %s\n", modeinfo[mode].filename);
1462                 }
1463         }
1464 }
1465
1466 void R_SetupShader_Generic(rtexture_t *t, qboolean usegamma, qboolean notrippy, qboolean suppresstexalpha)
1467 {
1468         dpuint64 permutation = 0;
1469         if (r_trippy.integer && !notrippy)
1470                 permutation |= SHADERPERMUTATION_TRIPPY;
1471         permutation |= SHADERPERMUTATION_VIEWTINT;
1472         if (t)
1473                 permutation |= SHADERPERMUTATION_DIFFUSE;
1474         if (usegamma && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
1475                 permutation |= SHADERPERMUTATION_GAMMARAMPS;
1476         if (suppresstexalpha)
1477                 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1478         if (vid.allowalphatocoverage)
1479                 GL_AlphaToCoverage(false);
1480         switch (vid.renderpath)
1481         {
1482         case RENDERPATH_GL32:
1483         case RENDERPATH_GLES2:
1484                 R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation);
1485                 if (r_glsl_permutation->tex_Texture_First >= 0)
1486                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First, t);
1487                 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0)
1488                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps);
1489                 break;
1490         }
1491 }
1492
1493 void R_SetupShader_Generic_NoTexture(qboolean usegamma, qboolean notrippy)
1494 {
1495         R_SetupShader_Generic(NULL, usegamma, notrippy, false);
1496 }
1497
1498 void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb, qboolean skeletal)
1499 {
1500         dpuint64 permutation = 0;
1501         if (r_trippy.integer && !notrippy)
1502                 permutation |= SHADERPERMUTATION_TRIPPY;
1503         if (depthrgb)
1504                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1505         if (skeletal)
1506                 permutation |= SHADERPERMUTATION_SKELETAL;
1507
1508         if (vid.allowalphatocoverage)
1509                 GL_AlphaToCoverage(false);
1510         switch (vid.renderpath)
1511         {
1512         case RENDERPATH_GL32:
1513         case RENDERPATH_GLES2:
1514                 R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
1515 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1516                 if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
1517 #endif
1518                 break;
1519         }
1520 }
1521
1522 #define BLENDFUNC_ALLOWS_COLORMOD      1
1523 #define BLENDFUNC_ALLOWS_FOG           2
1524 #define BLENDFUNC_ALLOWS_FOG_HACK0     4
1525 #define BLENDFUNC_ALLOWS_FOG_HACKALPHA 8
1526 #define BLENDFUNC_ALLOWS_ANYFOG        (BLENDFUNC_ALLOWS_FOG | BLENDFUNC_ALLOWS_FOG_HACK0 | BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1527 static int R_BlendFuncFlags(int src, int dst)
1528 {
1529         int r = 0;
1530
1531         // a blendfunc allows colormod if:
1532         // a) it can never keep the destination pixel invariant, or
1533         // b) it can keep the destination pixel invariant, and still can do so if colormodded
1534         // this is to prevent unintended side effects from colormod
1535
1536         // a blendfunc allows fog if:
1537         // blend(fog(src), fog(dst)) == fog(blend(src, dst))
1538         // this is to prevent unintended side effects from fog
1539
1540         // these checks are the output of fogeval.pl
1541
1542         r |= BLENDFUNC_ALLOWS_COLORMOD;
1543         if(src == GL_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1544         if(src == GL_DST_ALPHA && dst == GL_ONE_MINUS_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1545         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1546         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1547         if(src == GL_DST_COLOR && dst == GL_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1548         if(src == GL_DST_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1549         if(src == GL_DST_COLOR && dst == GL_ZERO) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1550         if(src == GL_ONE && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1551         if(src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG_HACKALPHA;
1552         if(src == GL_ONE && dst == GL_ZERO) r |= BLENDFUNC_ALLOWS_FOG;
1553         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1554         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1555         if(src == GL_ONE_MINUS_DST_COLOR && dst == GL_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1556         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1557         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1558         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1559         if(src == GL_ONE_MINUS_SRC_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1560         if(src == GL_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1561         if(src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1562         if(src == GL_ZERO && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG;
1563         if(src == GL_ZERO && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1564
1565         return r;
1566 }
1567
1568 void R_SetupShader_Surface(const float rtlightambient[3], const float rtlightdiffuse[3], const float rtlightspecular[3], rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist, void *surfacewaterplane, qboolean notrippy)
1569 {
1570         // select a permutation of the lighting shader appropriate to this
1571         // combination of texture, entity, light source, and fogging, only use the
1572         // minimum features necessary to avoid wasting rendering time in the
1573         // fragment shader on features that are not being used
1574         dpuint64 permutation = 0;
1575         unsigned int mode = 0;
1576         int blendfuncflags;
1577         texture_t *t = rsurface.texture;
1578         float m16f[16];
1579         matrix4x4_t tempmatrix;
1580         r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
1581         if (r_trippy.integer && !notrippy)
1582                 permutation |= SHADERPERMUTATION_TRIPPY;
1583         if (t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1584                 permutation |= SHADERPERMUTATION_ALPHAKILL;
1585         if (t->currentmaterialflags & MATERIALFLAG_OCCLUDE)
1586                 permutation |= SHADERPERMUTATION_OCCLUDE;
1587         if (t->r_water_waterscroll[0] && t->r_water_waterscroll[1])
1588                 permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
1589         if (rsurfacepass == RSURFPASS_BACKGROUND)
1590         {
1591                 // distorted background
1592                 if (t->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1593                 {
1594                         mode = SHADERMODE_WATER;
1595                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1596                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1597                         if((r_wateralpha.value < 1) && (t->currentmaterialflags & MATERIALFLAG_WATERALPHA))
1598                         {
1599                                 // this is the right thing to do for wateralpha
1600                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1601                                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1602                         }
1603                         else
1604                         {
1605                                 // this is the right thing to do for entity alpha
1606                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1607                                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1608                         }
1609                 }
1610                 else if (t->currentmaterialflags & MATERIALFLAG_REFRACTION)
1611                 {
1612                         mode = SHADERMODE_REFRACTION;
1613                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1614                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1615                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1616                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1617                 }
1618                 else
1619                 {
1620                         mode = SHADERMODE_GENERIC;
1621                         permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL;
1622                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1623                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1624                 }
1625                 if (vid.allowalphatocoverage)
1626                         GL_AlphaToCoverage(false);
1627         }
1628         else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
1629         {
1630                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1631                 {
1632                         switch(t->offsetmapping)
1633                         {
1634                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1635                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1636                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1637                         case OFFSETMAPPING_OFF: break;
1638                         }
1639                 }
1640                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1641                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1642                 // normalmap (deferred prepass), may use alpha test on diffuse
1643                 mode = SHADERMODE_DEFERREDGEOMETRY;
1644                 GL_BlendFunc(GL_ONE, GL_ZERO);
1645                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1646                 if (vid.allowalphatocoverage)
1647                         GL_AlphaToCoverage(false);
1648         }
1649         else if (rsurfacepass == RSURFPASS_RTLIGHT)
1650         {
1651                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1652                 {
1653                         switch(t->offsetmapping)
1654                         {
1655                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1656                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1657                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1658                         case OFFSETMAPPING_OFF: break;
1659                         }
1660                 }
1661                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1662                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1663                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1664                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1665                 // light source
1666                 mode = SHADERMODE_LIGHTSOURCE;
1667                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1668                         permutation |= SHADERPERMUTATION_CUBEFILTER;
1669                 if (VectorLength2(rtlightdiffuse) > 0)
1670                         permutation |= SHADERPERMUTATION_DIFFUSE;
1671                 if (VectorLength2(rtlightspecular) > 0)
1672                         permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1673                 if (r_refdef.fogenabled)
1674                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1675                 if (t->colormapping)
1676                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1677                 if (r_shadow_usingshadowmap2d)
1678                 {
1679                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1680                         if(r_shadow_shadowmapvsdct)
1681                                 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
1682
1683                         if (r_shadow_shadowmap2ddepthbuffer)
1684                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1685                 }
1686                 if (t->reflectmasktexture)
1687                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1688                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1689                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE);
1690                 if (vid.allowalphatocoverage)
1691                         GL_AlphaToCoverage(false);
1692         }
1693         else if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
1694         {
1695                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1696                 {
1697                         switch(t->offsetmapping)
1698                         {
1699                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1700                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1701                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1702                         case OFFSETMAPPING_OFF: break;
1703                         }
1704                 }
1705                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1706                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1707                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1708                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1709                 // directional model lighting
1710                 mode = SHADERMODE_LIGHTDIRECTION;
1711                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1712                         permutation |= SHADERPERMUTATION_GLOW;
1713                 if (VectorLength2(t->render_modellight_diffuse))
1714                         permutation |= SHADERPERMUTATION_DIFFUSE;
1715                 if (VectorLength2(t->render_modellight_specular) > 0)
1716                         permutation |= SHADERPERMUTATION_SPECULAR;
1717                 if (r_refdef.fogenabled)
1718                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1719                 if (t->colormapping)
1720                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1721                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1722                 {
1723                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1724                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1725
1726                         if (r_shadow_shadowmap2ddepthbuffer)
1727                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1728                 }
1729                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1730                         permutation |= SHADERPERMUTATION_REFLECTION;
1731                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1732                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1733                 if (t->reflectmasktexture)
1734                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1735                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1736                 {
1737                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1738                         if (r_shadow_bouncegrid_state.directional)
1739                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1740                 }
1741                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1742                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1743                 // when using alphatocoverage, we don't need alphakill
1744                 if (vid.allowalphatocoverage)
1745                 {
1746                         if (r_transparent_alphatocoverage.integer)
1747                         {
1748                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1749                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1750                         }
1751                         else
1752                                 GL_AlphaToCoverage(false);
1753                 }
1754         }
1755         else
1756         {
1757                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1758                 {
1759                         switch(t->offsetmapping)
1760                         {
1761                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1762                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1763                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1764                         case OFFSETMAPPING_OFF: break;
1765                         }
1766                 }
1767                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1768                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1769                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1770                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1771                 // lightmapped wall
1772                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1773                         permutation |= SHADERPERMUTATION_GLOW;
1774                 if (r_refdef.fogenabled)
1775                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1776                 if (t->colormapping)
1777                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1778                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1779                 {
1780                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1781                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1782
1783                         if (r_shadow_shadowmap2ddepthbuffer)
1784                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1785                 }
1786                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1787                         permutation |= SHADERPERMUTATION_REFLECTION;
1788                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1789                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1790                 if (t->reflectmasktexture)
1791                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1792                 if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
1793                 {
1794                         // deluxemapping (light direction texture)
1795                         if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace)
1796                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1797                         else
1798                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1799                         permutation |= SHADERPERMUTATION_DIFFUSE;
1800                         if (VectorLength2(t->render_lightmap_specular) > 0)
1801                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1802                 }
1803                 else if (r_glsl_deluxemapping.integer >= 2)
1804                 {
1805                         // fake deluxemapping (uniform light direction in tangentspace)
1806                         if (rsurface.uselightmaptexture)
1807                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP;
1808                         else
1809                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR;
1810                         permutation |= SHADERPERMUTATION_DIFFUSE;
1811                         if (VectorLength2(t->render_lightmap_specular) > 0)
1812                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1813                 }
1814                 else if (rsurface.uselightmaptexture)
1815                 {
1816                         // ordinary lightmapping (q1bsp, q3bsp)
1817                         mode = SHADERMODE_LIGHTMAP;
1818                 }
1819                 else
1820                 {
1821                         // ordinary vertex coloring (q3bsp)
1822                         mode = SHADERMODE_VERTEXCOLOR;
1823                 }
1824                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1825                 {
1826                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1827                         if (r_shadow_bouncegrid_state.directional)
1828                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1829                 }
1830                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1831                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1832                 // when using alphatocoverage, we don't need alphakill
1833                 if (vid.allowalphatocoverage)
1834                 {
1835                         if (r_transparent_alphatocoverage.integer)
1836                         {
1837                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1838                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1839                         }
1840                         else
1841                                 GL_AlphaToCoverage(false);
1842                 }
1843         }
1844         if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG))
1845                 permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE);
1846         if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1847                 permutation |= SHADERPERMUTATION_FOGALPHAHACK;
1848         switch(vid.renderpath)
1849         {
1850         case RENDERPATH_GL32:
1851         case RENDERPATH_GLES2:
1852                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | (rsurface.modellightmapcolor4f ? BATCHNEED_ARRAY_VERTEXCOLOR : 0) | BATCHNEED_ARRAY_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_ARRAY_LIGHTMAP : 0) | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
1853                 RSurf_UploadBuffersForBatch();
1854                 // this has to be after RSurf_PrepareVerticesForBatch
1855                 if (rsurface.batchskeletaltransform3x4buffer)
1856                         permutation |= SHADERPERMUTATION_SKELETAL;
1857                 R_SetupShader_SetPermutationGLSL(mode, permutation);
1858 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1859                 if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
1860 #endif
1861                 if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
1862                 if (mode == SHADERMODE_LIGHTSOURCE)
1863                 {
1864                         if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
1865                         if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1866                         if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1867                         if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
1868                         if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
1869                         if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
1870         
1871                         // additive passes are only darkened by fog, not tinted
1872                         if (r_glsl_permutation->loc_FogColor >= 0)
1873                                 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1874                         if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, t->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
1875                 }
1876                 else
1877                 {
1878                         if (mode == SHADERMODE_FLATCOLOR)
1879                         {
1880                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
1881                         }
1882                         else if (mode == SHADERMODE_LIGHTDIRECTION)
1883                         {
1884                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
1885                                 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_modellight_diffuse[0], t->render_modellight_diffuse[1], t->render_modellight_diffuse[2]);
1886                                 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_modellight_specular[0], t->render_modellight_specular[1], t->render_modellight_specular[2]);
1887                                 if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, t->render_rtlight_diffuse[0], t->render_rtlight_diffuse[1], t->render_rtlight_diffuse[2]);
1888                                 if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, t->render_rtlight_specular[0], t->render_rtlight_specular[1], t->render_rtlight_specular[2]);
1889                                 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1890                                 if (r_glsl_permutation->loc_LightDir >= 0) qglUniform3f(r_glsl_permutation->loc_LightDir, t->render_modellight_lightdir[0], t->render_modellight_lightdir[1], t->render_modellight_lightdir[2]);
1891                         }
1892                         else
1893                         {
1894                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_lightmap_ambient[0], t->render_lightmap_ambient[1], t->render_lightmap_ambient[2]);
1895                                 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_lightmap_diffuse[0], t->render_lightmap_diffuse[1], t->render_lightmap_diffuse[2]);
1896                                 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_lightmap_specular[0], t->render_lightmap_specular[1], t->render_lightmap_specular[2]);
1897                                 if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, t->render_rtlight_diffuse[0], t->render_rtlight_diffuse[1], t->render_rtlight_diffuse[2]);
1898                                 if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, t->render_rtlight_specular[0], t->render_rtlight_specular[1], t->render_rtlight_specular[2]);
1899                         }
1900                         // additive passes are only darkened by fog, not tinted
1901                         if (r_glsl_permutation->loc_FogColor >= 0)
1902                         {
1903                                 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
1904                                         qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1905                                 else
1906                                         qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1907                         }
1908                         if (r_glsl_permutation->loc_DistortScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_DistortScaleRefractReflect, r_water_refractdistort.value * t->refractfactor, r_water_refractdistort.value * t->refractfactor, r_water_reflectdistort.value * t->reflectfactor, r_water_reflectdistort.value * t->reflectfactor);
1909                         if (r_glsl_permutation->loc_ScreenScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenScaleRefractReflect, r_fb.water.screenscale[0], r_fb.water.screenscale[1], r_fb.water.screenscale[0], r_fb.water.screenscale[1]);
1910                         if (r_glsl_permutation->loc_ScreenCenterRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenCenterRefractReflect, r_fb.water.screencenter[0], r_fb.water.screencenter[1], r_fb.water.screencenter[0], r_fb.water.screencenter[1]);
1911                         if (r_glsl_permutation->loc_RefractColor >= 0) qglUniform4f(r_glsl_permutation->loc_RefractColor, t->refractcolor4f[0], t->refractcolor4f[1], t->refractcolor4f[2], t->refractcolor4f[3] * t->currentalpha);
1912                         if (r_glsl_permutation->loc_ReflectColor >= 0) qglUniform4f(r_glsl_permutation->loc_ReflectColor, t->reflectcolor4f[0], t->reflectcolor4f[1], t->reflectcolor4f[2], t->reflectcolor4f[3] * t->currentalpha);
1913                         if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, t->reflectmax - t->reflectmin);
1914                         if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, t->reflectmin);
1915                         if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, t->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
1916                         if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
1917                 }
1918                 if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
1919                 if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
1920                 if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
1921                 if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
1922                 {
1923                         if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_modelshadowmap_texturescale[0], r_shadow_modelshadowmap_texturescale[1], r_shadow_modelshadowmap_texturescale[2], r_shadow_modelshadowmap_texturescale[3]);
1924                         if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_modelshadowmap_parameters[0], r_shadow_modelshadowmap_parameters[1], r_shadow_modelshadowmap_parameters[2], r_shadow_modelshadowmap_parameters[3]);
1925                 }
1926                 else
1927                 {
1928                         if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
1929                         if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
1930                 }
1931
1932                 if (r_glsl_permutation->loc_Color_Glow >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Glow, t->render_glowmod[0], t->render_glowmod[1], t->render_glowmod[2]);
1933                 if (r_glsl_permutation->loc_Alpha >= 0) qglUniform1f(r_glsl_permutation->loc_Alpha, t->currentalpha * ((t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? t->r_water_wateralpha : 1));
1934                 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
1935                 if (r_glsl_permutation->loc_Color_Pants >= 0)
1936                 {
1937                         if (t->pantstexture)
1938                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
1939                         else
1940                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
1941                 }
1942                 if (r_glsl_permutation->loc_Color_Shirt >= 0)
1943                 {
1944                         if (t->shirttexture)
1945                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
1946                         else
1947                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
1948                 }
1949                 if (r_glsl_permutation->loc_FogPlane >= 0) qglUniform4f(r_glsl_permutation->loc_FogPlane, rsurface.fogplane[0], rsurface.fogplane[1], rsurface.fogplane[2], rsurface.fogplane[3]);
1950                 if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
1951                 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
1952                 if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
1953                 if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps,
1954                                 r_glsl_offsetmapping_scale.value*t->offsetscale,
1955                                 max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
1956                                 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
1957                                 max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
1958                         );
1959                 if (r_glsl_permutation->loc_OffsetMapping_LodDistance >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer * r_refdef.view.quality);
1960                 if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, t->offsetbias);
1961                 if (r_glsl_permutation->loc_ScreenToDepth >= 0) qglUniform2f(r_glsl_permutation->loc_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
1962                 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
1963                 if (r_glsl_permutation->loc_BounceGridMatrix >= 0) {Matrix4x4_Concat(&tempmatrix, &r_shadow_bouncegrid_state.matrix, &rsurface.matrix);Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BounceGridMatrix, 1, false, m16f);}
1964                 if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
1965
1966                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First            , r_texture_white                                     );
1967                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second           , r_texture_white                                     );
1968                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps       , r_texture_gammaramps                                );
1969                 if (r_glsl_permutation->tex_Texture_Normal          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal           , t->nmaptexture                       );
1970                 if (r_glsl_permutation->tex_Texture_Color           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color            , t->basetexture                       );
1971                 if (r_glsl_permutation->tex_Texture_Gloss           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss            , t->glosstexture                      );
1972                 if (r_glsl_permutation->tex_Texture_Glow            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow             , t->glowtexture                       );
1973                 if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal  , t->backgroundnmaptexture             );
1974                 if (r_glsl_permutation->tex_Texture_SecondaryColor  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor   , t->backgroundbasetexture             );
1975                 if (r_glsl_permutation->tex_Texture_SecondaryGloss  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss   , t->backgroundglosstexture            );
1976                 if (r_glsl_permutation->tex_Texture_SecondaryGlow   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow    , t->backgroundglowtexture             );
1977                 if (r_glsl_permutation->tex_Texture_Pants           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants            , t->pantstexture                      );
1978                 if (r_glsl_permutation->tex_Texture_Shirt           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt            , t->shirttexture                      );
1979                 if (r_glsl_permutation->tex_Texture_ReflectMask     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask      , t->reflectmasktexture                );
1980                 if (r_glsl_permutation->tex_Texture_ReflectCube     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube      , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
1981                 if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture                          );
1982                 if (r_glsl_permutation->tex_Texture_FogMask         >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask          , r_texture_fogattenuation                            );
1983                 if (r_glsl_permutation->tex_Texture_Lightmap        >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap         , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
1984                 if (r_glsl_permutation->tex_Texture_Deluxemap       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Deluxemap        , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap);
1985                 if (r_glsl_permutation->tex_Texture_Attenuation     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation      , r_shadow_attenuationgradienttexture                 );
1986                 if (rsurfacepass == RSURFPASS_BACKGROUND)
1987                 {
1988                         if (r_glsl_permutation->tex_Texture_Refraction  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Refraction        , waterplane->rt_refraction ? waterplane->rt_refraction->colortexture[0] : r_texture_black);
1989                         if (r_glsl_permutation->tex_Texture_First       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First             , waterplane->rt_camera ? waterplane->rt_camera->colortexture[0] : r_texture_black);
1990                         if (r_glsl_permutation->tex_Texture_Reflection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection        , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
1991                 }
1992                 else
1993                 {
1994                         if (r_glsl_permutation->tex_Texture_Reflection >= 0 && waterplane) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection        , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
1995                 }
1996                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap   , r_shadow_prepassgeometrynormalmaptexture            );
1997                 if (r_glsl_permutation->tex_Texture_ScreenDiffuse   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse     , r_shadow_prepasslightingdiffusetexture              );
1998                 if (r_glsl_permutation->tex_Texture_ScreenSpecular  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular    , r_shadow_prepasslightingspeculartexture             );
1999                 if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
2000                 {
2001                         if (r_glsl_permutation->tex_Texture_ShadowMap2D     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture                           );
2002                         if (rsurface.rtlight)
2003                         {
2004                                 if (r_glsl_permutation->tex_Texture_Cube            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube              , rsurface.rtlight->currentcubemap                    );
2005                                 if (r_glsl_permutation->tex_Texture_CubeProjection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection    , r_shadow_shadowmapvsdcttexture                      );
2006                         }
2007                 }
2008                 if (r_glsl_permutation->tex_Texture_BounceGrid  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
2009                 CHECKGLERROR
2010                 break;
2011         }
2012 }
2013
2014 void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
2015 {
2016         // select a permutation of the lighting shader appropriate to this
2017         // combination of texture, entity, light source, and fogging, only use the
2018         // minimum features necessary to avoid wasting rendering time in the
2019         // fragment shader on features that are not being used
2020         dpuint64 permutation = 0;
2021         unsigned int mode = 0;
2022         const float *lightcolorbase = rtlight->currentcolor;
2023         float ambientscale = rtlight->ambientscale;
2024         float diffusescale = rtlight->diffusescale;
2025         float specularscale = rtlight->specularscale;
2026         // this is the location of the light in view space
2027         vec3_t viewlightorigin;
2028         // this transforms from view space (camera) to light space (cubemap)
2029         matrix4x4_t viewtolight;
2030         matrix4x4_t lighttoview;
2031         float viewtolight16f[16];
2032         // light source
2033         mode = SHADERMODE_DEFERREDLIGHTSOURCE;
2034         if (rtlight->currentcubemap != r_texture_whitecube)
2035                 permutation |= SHADERPERMUTATION_CUBEFILTER;
2036         if (diffusescale > 0)
2037                 permutation |= SHADERPERMUTATION_DIFFUSE;
2038         if (specularscale > 0 && r_shadow_gloss.integer > 0)
2039                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2040         if (r_shadow_usingshadowmap2d)
2041         {
2042                 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
2043                 if (r_shadow_shadowmapvsdct)
2044                         permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
2045
2046                 if (r_shadow_shadowmap2ddepthbuffer)
2047                         permutation |= SHADERPERMUTATION_DEPTHRGB;
2048         }
2049         if (vid.allowalphatocoverage)
2050                 GL_AlphaToCoverage(false);
2051         Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
2052         Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
2053         Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
2054         Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
2055         switch(vid.renderpath)
2056         {
2057         case RENDERPATH_GL32:
2058         case RENDERPATH_GLES2:
2059                 R_SetupShader_SetPermutationGLSL(mode, permutation);
2060                 if (r_glsl_permutation->loc_LightPosition             >= 0) qglUniform3f(       r_glsl_permutation->loc_LightPosition            , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
2061                 if (r_glsl_permutation->loc_ViewToLight               >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight              , 1, false, viewtolight16f);
2062                 if (r_glsl_permutation->loc_DeferredColor_Ambient     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Ambient    , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
2063                 if (r_glsl_permutation->loc_DeferredColor_Diffuse     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
2064                 if (r_glsl_permutation->loc_DeferredColor_Specular    >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Specular   , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
2065                 if (r_glsl_permutation->loc_ShadowMap_TextureScale    >= 0) qglUniform4f(       r_glsl_permutation->loc_ShadowMap_TextureScale   , r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
2066                 if (r_glsl_permutation->loc_ShadowMap_Parameters      >= 0) qglUniform4f(       r_glsl_permutation->loc_ShadowMap_Parameters     , r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
2067                 if (r_glsl_permutation->loc_SpecularPower             >= 0) qglUniform1f(       r_glsl_permutation->loc_SpecularPower            , (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
2068                 if (r_glsl_permutation->loc_ScreenToDepth             >= 0) qglUniform2f(       r_glsl_permutation->loc_ScreenToDepth            , r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
2069                 if (r_glsl_permutation->loc_PixelToScreenTexCoord     >= 0) qglUniform2f(       r_glsl_permutation->loc_PixelToScreenTexCoord    , 1.0f/vid.width, 1.0f/vid.height);
2070
2071                 if (r_glsl_permutation->tex_Texture_Attenuation       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation        , r_shadow_attenuationgradienttexture                 );
2072                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap    , r_shadow_prepassgeometrynormalmaptexture            );
2073                 if (r_glsl_permutation->tex_Texture_Cube              >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube               , rsurface.rtlight->currentcubemap                    );
2074                 if (r_glsl_permutation->tex_Texture_ShadowMap2D       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D        , r_shadow_shadowmap2ddepthtexture                    );
2075                 if (r_glsl_permutation->tex_Texture_CubeProjection    >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection     , r_shadow_shadowmapvsdcttexture                      );
2076                 break;
2077         }
2078 }
2079
2080 #define SKINFRAME_HASH 1024
2081
2082 typedef struct
2083 {
2084         unsigned int loadsequence; // incremented each level change
2085         memexpandablearray_t array;
2086         skinframe_t *hash[SKINFRAME_HASH];
2087 }
2088 r_skinframe_t;
2089 r_skinframe_t r_skinframe;
2090
2091 void R_SkinFrame_PrepareForPurge(void)
2092 {
2093         r_skinframe.loadsequence++;
2094         // wrap it without hitting zero
2095         if (r_skinframe.loadsequence >= 200)
2096                 r_skinframe.loadsequence = 1;
2097 }
2098
2099 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
2100 {
2101         if (!skinframe)
2102                 return;
2103         // mark the skinframe as used for the purging code
2104         skinframe->loadsequence = r_skinframe.loadsequence;
2105 }
2106
2107 void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
2108 {
2109         if (s == NULL)
2110                 return;
2111         if (s->merged == s->base)
2112                 s->merged = NULL;
2113         R_PurgeTexture(s->stain); s->stain = NULL;
2114         R_PurgeTexture(s->merged); s->merged = NULL;
2115         R_PurgeTexture(s->base); s->base = NULL;
2116         R_PurgeTexture(s->pants); s->pants = NULL;
2117         R_PurgeTexture(s->shirt); s->shirt = NULL;
2118         R_PurgeTexture(s->nmap); s->nmap = NULL;
2119         R_PurgeTexture(s->gloss); s->gloss = NULL;
2120         R_PurgeTexture(s->glow); s->glow = NULL;
2121         R_PurgeTexture(s->fog); s->fog = NULL;
2122         R_PurgeTexture(s->reflect); s->reflect = NULL;
2123         s->loadsequence = 0;
2124 }
2125
2126 void R_SkinFrame_Purge(void)
2127 {
2128         int i;
2129         skinframe_t *s;
2130         for (i = 0;i < SKINFRAME_HASH;i++)
2131         {
2132                 for (s = r_skinframe.hash[i];s;s = s->next)
2133                 {
2134                         if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
2135                                 R_SkinFrame_PurgeSkinFrame(s);
2136                 }
2137         }
2138 }
2139
2140 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
2141         skinframe_t *item;
2142         char basename[MAX_QPATH];
2143
2144         Image_StripImageExtension(name, basename, sizeof(basename));
2145
2146         if( last == NULL ) {
2147                 int hashindex;
2148                 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2149                 item = r_skinframe.hash[hashindex];
2150         } else {
2151                 item = last->next;
2152         }
2153
2154         // linearly search through the hash bucket
2155         for( ; item ; item = item->next ) {
2156                 if( !strcmp( item->basename, basename ) ) {
2157                         return item;
2158                 }
2159         }
2160         return NULL;
2161 }
2162
2163 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add)
2164 {
2165         skinframe_t *item;
2166         int compareflags = textureflags & TEXF_IMPORTANTBITS;
2167         int hashindex;
2168         char basename[MAX_QPATH];
2169
2170         Image_StripImageExtension(name, basename, sizeof(basename));
2171
2172         hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2173         for (item = r_skinframe.hash[hashindex];item;item = item->next)
2174                 if (!strcmp(item->basename, basename) &&
2175                         item->textureflags == compareflags &&
2176                         item->comparewidth == comparewidth &&
2177                         item->compareheight == compareheight &&
2178                         item->comparecrc == comparecrc)
2179                         break;
2180
2181         if (!item)
2182         {
2183                 if (!add)
2184                         return NULL;
2185                 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
2186                 memset(item, 0, sizeof(*item));
2187                 strlcpy(item->basename, basename, sizeof(item->basename));
2188                 item->textureflags = compareflags;
2189                 item->comparewidth = comparewidth;
2190                 item->compareheight = compareheight;
2191                 item->comparecrc = comparecrc;
2192                 item->next = r_skinframe.hash[hashindex];
2193                 r_skinframe.hash[hashindex] = item;
2194         }
2195         else if (textureflags & TEXF_FORCE_RELOAD)
2196                 R_SkinFrame_PurgeSkinFrame(item);
2197
2198         R_SkinFrame_MarkUsed(item);
2199         return item;
2200 }
2201
2202 #define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
2203         { \
2204                 unsigned long long avgcolor[5], wsum; \
2205                 int pix, comp, w; \
2206                 avgcolor[0] = 0; \
2207                 avgcolor[1] = 0; \
2208                 avgcolor[2] = 0; \
2209                 avgcolor[3] = 0; \
2210                 avgcolor[4] = 0; \
2211                 wsum = 0; \
2212                 for(pix = 0; pix < cnt; ++pix) \
2213                 { \
2214                         w = 0; \
2215                         for(comp = 0; comp < 3; ++comp) \
2216                                 w += getpixel; \
2217                         if(w) /* ignore perfectly black pixels because that is better for model skins */ \
2218                         { \
2219                                 ++wsum; \
2220                                 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2221                                 w = getpixel; \
2222                                 for(comp = 0; comp < 3; ++comp) \
2223                                         avgcolor[comp] += getpixel * w; \
2224                                 avgcolor[3] += w; \
2225                         } \
2226                         /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2227                         avgcolor[4] += getpixel; \
2228                 } \
2229                 if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
2230                         avgcolor[3] = 1; \
2231                 skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
2232                 skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
2233                 skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
2234                 skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
2235         }
2236
2237 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2238 {
2239         skinframe_t *skinframe;
2240
2241         if (cls.state == ca_dedicated)
2242                 return NULL;
2243
2244         // return an existing skinframe if already loaded
2245         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
2246         if (skinframe && skinframe->base)
2247                 return skinframe;
2248
2249         // if the skinframe doesn't exist this will create it
2250         return R_SkinFrame_LoadExternal_SkinFrame(skinframe, name, textureflags, complain, fallbacknotexture);
2251 }
2252
2253 extern cvar_t gl_picmip;
2254 skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2255 {
2256         int j;
2257         unsigned char *pixels;
2258         unsigned char *bumppixels;
2259         unsigned char *basepixels = NULL;
2260         int basepixels_width = 0;
2261         int basepixels_height = 0;
2262         rtexture_t *ddsbase = NULL;
2263         qboolean ddshasalpha = false;
2264         float ddsavgcolor[4];
2265         char basename[MAX_QPATH];
2266         int miplevel = R_PicmipForFlags(textureflags);
2267         int savemiplevel = miplevel;
2268         int mymiplevel;
2269         char vabuf[1024];
2270
2271         if (cls.state == ca_dedicated)
2272                 return NULL;
2273
2274         Image_StripImageExtension(name, basename, sizeof(basename));
2275
2276         // check for DDS texture file first
2277         if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2278         {
2279                 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2280                 if (basepixels == NULL && fallbacknotexture)
2281                         basepixels = Image_GenerateNoTexture();
2282                 if (basepixels == NULL)
2283                         return NULL;
2284         }
2285
2286         // FIXME handle miplevel
2287
2288         if (developer_loading.integer)
2289                 Con_Printf("loading skin \"%s\"\n", name);
2290
2291         // we've got some pixels to store, so really allocate this new texture now
2292         if (!skinframe)
2293                 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2294         textureflags &= ~TEXF_FORCE_RELOAD;
2295         skinframe->stain = NULL;
2296         skinframe->merged = NULL;
2297         skinframe->base = NULL;
2298         skinframe->pants = NULL;
2299         skinframe->shirt = NULL;
2300         skinframe->nmap = NULL;
2301         skinframe->gloss = NULL;
2302         skinframe->glow = NULL;
2303         skinframe->fog = NULL;
2304         skinframe->reflect = NULL;
2305         skinframe->hasalpha = false;
2306         // we could store the q2animname here too
2307
2308         if (ddsbase)
2309         {
2310                 skinframe->base = ddsbase;
2311                 skinframe->hasalpha = ddshasalpha;
2312                 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2313                 if (r_loadfog && skinframe->hasalpha)
2314                         skinframe->fog = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), false, textureflags | TEXF_ALPHA, NULL, NULL, miplevel, true);
2315                 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2316         }
2317         else
2318         {
2319                 basepixels_width = image_width;
2320                 basepixels_height = image_height;
2321                 skinframe->base = R_LoadTexture2D (r_main_texturepool, skinframe->basename, basepixels_width, basepixels_height, basepixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL);
2322                 if (textureflags & TEXF_ALPHA)
2323                 {
2324                         for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2325                         {
2326                                 if (basepixels[j] < 255)
2327                                 {
2328                                         skinframe->hasalpha = true;
2329                                         break;
2330                                 }
2331                         }
2332                         if (r_loadfog && skinframe->hasalpha)
2333                         {
2334                                 // has transparent pixels
2335                                 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2336                                 for (j = 0;j < image_width * image_height * 4;j += 4)
2337                                 {
2338                                         pixels[j+0] = 255;
2339                                         pixels[j+1] = 255;
2340                                         pixels[j+2] = 255;
2341                                         pixels[j+3] = basepixels[j+3];
2342                                 }
2343                                 skinframe->fog = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_mask", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL);
2344                                 Mem_Free(pixels);
2345                         }
2346                 }
2347                 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2348 #ifndef USE_GLES2
2349                 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2350                 if (r_savedds && skinframe->base)
2351                         R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2352                 if (r_savedds && skinframe->fog)
2353                         R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2354 #endif
2355         }
2356
2357         if (r_loaddds)
2358         {
2359                 mymiplevel = savemiplevel;
2360                 if (r_loadnormalmap)
2361                         skinframe->nmap = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), false, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), NULL, NULL, mymiplevel, true);
2362                 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2363                 if (r_loadgloss)
2364                         skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2365                 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2366                 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2367                 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2368         }
2369
2370         // _norm is the name used by tenebrae and has been adopted as standard
2371         if (r_loadnormalmap && skinframe->nmap == NULL)
2372         {
2373                 mymiplevel = savemiplevel;
2374                 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2375                 {
2376                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2377                         Mem_Free(pixels);
2378                         pixels = NULL;
2379                 }
2380                 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2381                 {
2382                         pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2383                         Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2384                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2385                         Mem_Free(pixels);
2386                         Mem_Free(bumppixels);
2387                 }
2388                 else if (r_shadow_bumpscale_basetexture.value > 0)
2389                 {
2390                         pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2391                         Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2392                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), basepixels_width, basepixels_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2393                         Mem_Free(pixels);
2394                 }
2395 #ifndef USE_GLES2
2396                 if (r_savedds && skinframe->nmap)
2397                         R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2398 #endif
2399         }
2400
2401         // _luma is supported only for tenebrae compatibility
2402         // _glow is the preferred name
2403         mymiplevel = savemiplevel;
2404         if (skinframe->glow == NULL && ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_glow",  skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_luma", skinframe->basename), false, false, false, &mymiplevel))))
2405         {
2406                 skinframe->glow = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_glow.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2407 #ifndef USE_GLES2
2408                 if (r_savedds && skinframe->glow)
2409                         R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2410 #endif
2411                 Mem_Free(pixels);pixels = NULL;
2412         }
2413
2414         mymiplevel = savemiplevel;
2415         if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2416         {
2417                 skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (gl_texturecompression_gloss.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2418 #ifndef USE_GLES2
2419                 if (r_savedds && skinframe->gloss)
2420                         R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2421 #endif
2422                 Mem_Free(pixels);
2423                 pixels = NULL;
2424         }
2425
2426         mymiplevel = savemiplevel;
2427         if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2428         {
2429                 skinframe->pants = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2430 #ifndef USE_GLES2
2431                 if (r_savedds && skinframe->pants)
2432                         R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2433 #endif
2434                 Mem_Free(pixels);
2435                 pixels = NULL;
2436         }
2437
2438         mymiplevel = savemiplevel;
2439         if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2440         {
2441                 skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2442 #ifndef USE_GLES2
2443                 if (r_savedds && skinframe->shirt)
2444                         R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2445 #endif
2446                 Mem_Free(pixels);
2447                 pixels = NULL;
2448         }
2449
2450         mymiplevel = savemiplevel;
2451         if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2452         {
2453                 skinframe->reflect = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_reflectmask.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2454 #ifndef USE_GLES2
2455                 if (r_savedds && skinframe->reflect)
2456                         R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2457 #endif
2458                 Mem_Free(pixels);
2459                 pixels = NULL;
2460         }
2461
2462         if (basepixels)
2463                 Mem_Free(basepixels);
2464
2465         return skinframe;
2466 }
2467
2468 skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, int comparewidth, int compareheight, int comparecrc, qboolean sRGB)
2469 {
2470         int i;
2471         skinframe_t *skinframe;
2472         char vabuf[1024];
2473
2474         if (cls.state == ca_dedicated)
2475                 return NULL;
2476
2477         // if already loaded just return it, otherwise make a new skinframe
2478         skinframe = R_SkinFrame_Find(name, textureflags, comparewidth, compareheight, comparecrc, true);
2479         if (skinframe->base)
2480                 return skinframe;
2481         textureflags &= ~TEXF_FORCE_RELOAD;
2482
2483         skinframe->stain = NULL;
2484         skinframe->merged = NULL;
2485         skinframe->base = NULL;
2486         skinframe->pants = NULL;
2487         skinframe->shirt = NULL;
2488         skinframe->nmap = NULL;
2489         skinframe->gloss = NULL;
2490         skinframe->glow = NULL;
2491         skinframe->fog = NULL;
2492         skinframe->reflect = NULL;
2493         skinframe->hasalpha = false;
2494
2495         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2496         if (!skindata)
2497                 return NULL;
2498
2499         if (developer_loading.integer)
2500                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2501
2502         if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2503         {
2504                 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2505                 unsigned char *b = a + width * height * 4;
2506                 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2507                 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, b, TEXTYPE_BGRA, (textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
2508                 Mem_Free(a);
2509         }
2510         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2511         if (textureflags & TEXF_ALPHA)
2512         {
2513                 for (i = 3;i < width * height * 4;i += 4)
2514                 {
2515                         if (skindata[i] < 255)
2516                         {
2517                                 skinframe->hasalpha = true;
2518                                 break;
2519                         }
2520                 }
2521                 if (r_loadfog && skinframe->hasalpha)
2522                 {
2523                         unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2524                         memcpy(fogpixels, skindata, width * height * 4);
2525                         for (i = 0;i < width * height * 4;i += 4)
2526                                 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2527                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2528                         Mem_Free(fogpixels);
2529                 }
2530         }
2531
2532         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2533         //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2534
2535         return skinframe;
2536 }
2537
2538 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2539 {
2540         int i;
2541         int featuresmask;
2542         skinframe_t *skinframe;
2543
2544         if (cls.state == ca_dedicated)
2545                 return NULL;
2546
2547         // if already loaded just return it, otherwise make a new skinframe
2548         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2549         if (skinframe->base)
2550                 return skinframe;
2551         //textureflags &= ~TEXF_FORCE_RELOAD;
2552
2553         skinframe->stain = NULL;
2554         skinframe->merged = NULL;
2555         skinframe->base = NULL;
2556         skinframe->pants = NULL;
2557         skinframe->shirt = NULL;
2558         skinframe->nmap = NULL;
2559         skinframe->gloss = NULL;
2560         skinframe->glow = NULL;
2561         skinframe->fog = NULL;
2562         skinframe->reflect = NULL;
2563         skinframe->hasalpha = false;
2564
2565         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2566         if (!skindata)
2567                 return NULL;
2568
2569         if (developer_loading.integer)
2570                 Con_Printf("loading quake skin \"%s\"\n", name);
2571
2572         // we actually don't upload anything until the first use, because mdl skins frequently go unused, and are almost never used in both modes (colormapped and non-colormapped)
2573         skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2574         memcpy(skinframe->qpixels, skindata, width*height);
2575         skinframe->qwidth = width;
2576         skinframe->qheight = height;
2577
2578         featuresmask = 0;
2579         for (i = 0;i < width * height;i++)
2580                 featuresmask |= palette_featureflags[skindata[i]];
2581
2582         skinframe->hasalpha = false;
2583         // fence textures
2584         if (name[0] == '{')
2585                 skinframe->hasalpha = true;
2586         skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2587         skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2588         skinframe->qgeneratemerged = true;
2589         skinframe->qgeneratebase = skinframe->qhascolormapping;
2590         skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2591
2592         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2593         //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2594
2595         return skinframe;
2596 }
2597
2598 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboolean colormapped)
2599 {
2600         int width;
2601         int height;
2602         unsigned char *skindata;
2603         char vabuf[1024];
2604
2605         if (!skinframe->qpixels)
2606                 return;
2607
2608         if (!skinframe->qhascolormapping)
2609                 colormapped = false;
2610
2611         if (colormapped)
2612         {
2613                 if (!skinframe->qgeneratebase)
2614                         return;
2615         }
2616         else
2617         {
2618                 if (!skinframe->qgeneratemerged)
2619                         return;
2620         }
2621
2622         width = skinframe->qwidth;
2623         height = skinframe->qheight;
2624         skindata = skinframe->qpixels;
2625
2626         if (skinframe->qgeneratenmap)
2627         {
2628                 unsigned char *a, *b;
2629                 skinframe->qgeneratenmap = false;
2630                 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2631                 b = a + width * height * 4;
2632                 // use either a custom palette or the quake palette
2633                 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2634                 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2635                 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, b, TEXTYPE_BGRA, (skinframe->textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
2636                 Mem_Free(a);
2637         }
2638
2639         if (skinframe->qgenerateglow)
2640         {
2641                 skinframe->qgenerateglow = false;
2642                 if (skinframe->hasalpha) // fence textures
2643                         skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags | TEXF_ALPHA, -1, palette_bgra_onlyfullbrights_transparent); // glow
2644                 else
2645                         skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_onlyfullbrights); // glow
2646         }
2647
2648         if (colormapped)
2649         {
2650                 skinframe->qgeneratebase = false;
2651                 skinframe->base  = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nospecial", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nocolormapnofullbrights : palette_bgra_nocolormap);
2652                 skinframe->pants = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_pantsaswhite);
2653                 skinframe->shirt = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_shirtaswhite);
2654         }
2655         else
2656         {
2657                 skinframe->qgeneratemerged = false;
2658                 if (skinframe->hasalpha) // fence textures
2659                         skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags | TEXF_ALPHA, -1, skinframe->glow ? palette_bgra_nofullbrights_transparent : palette_bgra_transparent);
2660                 else
2661                         skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nofullbrights : palette_bgra_complete);
2662         }
2663
2664         if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2665         {
2666                 Mem_Free(skinframe->qpixels);
2667                 skinframe->qpixels = NULL;
2668         }
2669 }
2670
2671 skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, const unsigned char *skindata, int width, int height, const unsigned int *palette, const unsigned int *alphapalette)
2672 {
2673         int i;
2674         skinframe_t *skinframe;
2675         char vabuf[1024];
2676
2677         if (cls.state == ca_dedicated)
2678                 return NULL;
2679
2680         // if already loaded just return it, otherwise make a new skinframe
2681         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2682         if (skinframe->base)
2683                 return skinframe;
2684         textureflags &= ~TEXF_FORCE_RELOAD;
2685
2686         skinframe->stain = NULL;
2687         skinframe->merged = NULL;
2688         skinframe->base = NULL;
2689         skinframe->pants = NULL;
2690         skinframe->shirt = NULL;
2691         skinframe->nmap = NULL;
2692         skinframe->gloss = NULL;
2693         skinframe->glow = NULL;
2694         skinframe->fog = NULL;
2695         skinframe->reflect = NULL;
2696         skinframe->hasalpha = false;
2697
2698         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2699         if (!skindata)
2700                 return NULL;
2701
2702         if (developer_loading.integer)
2703                 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2704
2705         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2706         if ((textureflags & TEXF_ALPHA) && alphapalette)
2707         {
2708                 for (i = 0;i < width * height;i++)
2709                 {
2710                         if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2711                         {
2712                                 skinframe->hasalpha = true;
2713                                 break;
2714                         }
2715                 }
2716                 if (r_loadfog && skinframe->hasalpha)
2717                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2718         }
2719
2720         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2721         //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2722
2723         return skinframe;
2724 }
2725
2726 skinframe_t *R_SkinFrame_LoadMissing(void)
2727 {
2728         skinframe_t *skinframe;
2729
2730         if (cls.state == ca_dedicated)
2731                 return NULL;
2732
2733         skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2734         skinframe->stain = NULL;
2735         skinframe->merged = NULL;
2736         skinframe->base = NULL;
2737         skinframe->pants = NULL;
2738         skinframe->shirt = NULL;
2739         skinframe->nmap = NULL;
2740         skinframe->gloss = NULL;
2741         skinframe->glow = NULL;
2742         skinframe->fog = NULL;
2743         skinframe->reflect = NULL;
2744         skinframe->hasalpha = false;
2745
2746         skinframe->avgcolor[0] = rand() / RAND_MAX;
2747         skinframe->avgcolor[1] = rand() / RAND_MAX;
2748         skinframe->avgcolor[2] = rand() / RAND_MAX;
2749         skinframe->avgcolor[3] = 1;
2750
2751         return skinframe;
2752 }
2753
2754 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2755 {
2756         int x, y;
2757         static unsigned char pix[16][16][4];
2758
2759         if (cls.state == ca_dedicated)
2760                 return NULL;
2761
2762         // this makes a light grey/dark grey checkerboard texture
2763         if (!pix[0][0][3])
2764         {
2765                 for (y = 0; y < 16; y++)
2766                 {
2767                         for (x = 0; x < 16; x++)
2768                         {
2769                                 if ((y < 8) ^ (x < 8))
2770                                 {
2771                                         pix[y][x][0] = 128;
2772                                         pix[y][x][1] = 128;
2773                                         pix[y][x][2] = 128;
2774                                         pix[y][x][3] = 255;
2775                                 }
2776                                 else
2777                                 {
2778                                         pix[y][x][0] = 64;
2779                                         pix[y][x][1] = 64;
2780                                         pix[y][x][2] = 64;
2781                                         pix[y][x][3] = 255;
2782                                 }
2783                         }
2784                 }
2785         }
2786
2787         return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, pix[0][0], 16, 16, 0, 0, 0, false);
2788 }
2789
2790 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qboolean sRGB)
2791 {
2792         skinframe_t *skinframe;
2793         if (cls.state == ca_dedicated)
2794                 return NULL;
2795         // if already loaded just return it, otherwise make a new skinframe
2796         skinframe = R_SkinFrame_Find(name, textureflags, width, height, 0, true);
2797         if (skinframe->base)
2798                 return skinframe;
2799         textureflags &= ~TEXF_FORCE_RELOAD;
2800         skinframe->stain = NULL;
2801         skinframe->merged = NULL;
2802         skinframe->base = NULL;
2803         skinframe->pants = NULL;
2804         skinframe->shirt = NULL;
2805         skinframe->nmap = NULL;
2806         skinframe->gloss = NULL;
2807         skinframe->glow = NULL;
2808         skinframe->fog = NULL;
2809         skinframe->reflect = NULL;
2810         skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2811         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2812         if (!tex)
2813                 return NULL;
2814         if (developer_loading.integer)
2815                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2816         skinframe->base = skinframe->merged = tex;
2817         Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2818         return skinframe;
2819 }
2820
2821 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2822 typedef struct suffixinfo_s
2823 {
2824         const char *suffix;
2825         qboolean flipx, flipy, flipdiagonal;
2826 }
2827 suffixinfo_t;
2828 static suffixinfo_t suffix[3][6] =
2829 {
2830         {
2831                 {"px",   false, false, false},
2832                 {"nx",   false, false, false},
2833                 {"py",   false, false, false},
2834                 {"ny",   false, false, false},
2835                 {"pz",   false, false, false},
2836                 {"nz",   false, false, false}
2837         },
2838         {
2839                 {"posx", false, false, false},
2840                 {"negx", false, false, false},
2841                 {"posy", false, false, false},
2842                 {"negy", false, false, false},
2843                 {"posz", false, false, false},
2844                 {"negz", false, false, false}
2845         },
2846         {
2847                 {"rt",    true, false,  true},
2848                 {"lf",   false,  true,  true},
2849                 {"ft",    true,  true, false},
2850                 {"bk",   false, false, false},
2851                 {"up",    true, false,  true},
2852                 {"dn",    true, false,  true}
2853         }
2854 };
2855
2856 static int componentorder[4] = {0, 1, 2, 3};
2857
2858 static rtexture_t *R_LoadCubemap(const char *basename)
2859 {
2860         int i, j, cubemapsize;
2861         unsigned char *cubemappixels, *image_buffer;
2862         rtexture_t *cubemaptexture;
2863         char name[256];
2864         // must start 0 so the first loadimagepixels has no requested width/height
2865         cubemapsize = 0;
2866         cubemappixels = NULL;
2867         cubemaptexture = NULL;
2868         // keep trying different suffix groups (posx, px, rt) until one loads
2869         for (j = 0;j < 3 && !cubemappixels;j++)
2870         {
2871                 // load the 6 images in the suffix group
2872                 for (i = 0;i < 6;i++)
2873                 {
2874                         // generate an image name based on the base and and suffix
2875                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2876                         // load it
2877                         if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
2878                         {
2879                                 // an image loaded, make sure width and height are equal
2880                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
2881                                 {
2882                                         // if this is the first image to load successfully, allocate the cubemap memory
2883                                         if (!cubemappixels && image_width >= 1)
2884                                         {
2885                                                 cubemapsize = image_width;
2886                                                 // note this clears to black, so unavailable sides are black
2887                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2888                                         }
2889                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2890                                         if (cubemappixels)
2891                                                 Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_buffer, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder);
2892                                 }
2893                                 else
2894                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2895                                 // free the image
2896                                 Mem_Free(image_buffer);
2897                         }
2898                 }
2899         }
2900         // if a cubemap loaded, upload it
2901         if (cubemappixels)
2902         {
2903                 if (developer_loading.integer)
2904                         Con_Printf("loading cubemap \"%s\"\n", basename);
2905
2906                 cubemaptexture = R_LoadTextureCubeMap(r_main_texturepool, basename, cubemapsize, cubemappixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, (gl_texturecompression_lightcubemaps.integer && gl_texturecompression.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
2907                 Mem_Free(cubemappixels);
2908         }
2909         else
2910         {
2911                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
2912                 if (developer_loading.integer)
2913                 {
2914                         Con_Printf("(tried tried images ");
2915                         for (j = 0;j < 3;j++)
2916                                 for (i = 0;i < 6;i++)
2917                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2918                         Con_Print(" and was unable to find any of them).\n");
2919                 }
2920         }
2921         return cubemaptexture;
2922 }
2923
2924 rtexture_t *R_GetCubemap(const char *basename)
2925 {
2926         int i;
2927         for (i = 0;i < r_texture_numcubemaps;i++)
2928                 if (r_texture_cubemaps[i] != NULL)
2929                         if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
2930                                 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
2931         if (i >= MAX_CUBEMAPS || !r_main_mempool)
2932                 return r_texture_whitecube;
2933         r_texture_numcubemaps++;
2934         r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
2935         strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
2936         r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
2937         return r_texture_cubemaps[i]->texture;
2938 }
2939
2940 static void R_Main_FreeViewCache(void)
2941 {
2942         if (r_refdef.viewcache.entityvisible)
2943                 Mem_Free(r_refdef.viewcache.entityvisible);
2944         if (r_refdef.viewcache.world_pvsbits)
2945                 Mem_Free(r_refdef.viewcache.world_pvsbits);
2946         if (r_refdef.viewcache.world_leafvisible)
2947                 Mem_Free(r_refdef.viewcache.world_leafvisible);
2948         if (r_refdef.viewcache.world_surfacevisible)
2949                 Mem_Free(r_refdef.viewcache.world_surfacevisible);
2950         memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
2951 }
2952
2953 static void R_Main_ResizeViewCache(void)
2954 {
2955         int numentities = r_refdef.scene.numentities;
2956         int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
2957         int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
2958         int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
2959         int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
2960         if (r_refdef.viewcache.maxentities < numentities)
2961         {
2962                 r_refdef.viewcache.maxentities = numentities;
2963                 if (r_refdef.viewcache.entityvisible)
2964                         Mem_Free(r_refdef.viewcache.entityvisible);
2965                 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
2966         }
2967         if (r_refdef.viewcache.world_numclusters != numclusters)
2968         {
2969                 r_refdef.viewcache.world_numclusters = numclusters;
2970                 r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
2971                 if (r_refdef.viewcache.world_pvsbits)
2972                         Mem_Free(r_refdef.viewcache.world_pvsbits);
2973                 r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
2974         }
2975         if (r_refdef.viewcache.world_numleafs != numleafs)
2976         {
2977                 r_refdef.viewcache.world_numleafs = numleafs;
2978                 if (r_refdef.viewcache.world_leafvisible)
2979                         Mem_Free(r_refdef.viewcache.world_leafvisible);
2980                 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
2981         }
2982         if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
2983         {
2984                 r_refdef.viewcache.world_numsurfaces = numsurfaces;
2985                 if (r_refdef.viewcache.world_surfacevisible)
2986                         Mem_Free(r_refdef.viewcache.world_surfacevisible);
2987                 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
2988         }
2989 }
2990
2991 extern rtexture_t *loadingscreentexture;
2992 static void gl_main_start(void)
2993 {
2994         loadingscreentexture = NULL;
2995         r_texture_blanknormalmap = NULL;
2996         r_texture_white = NULL;
2997         r_texture_grey128 = NULL;
2998         r_texture_black = NULL;
2999         r_texture_whitecube = NULL;
3000         r_texture_normalizationcube = NULL;
3001         r_texture_fogattenuation = NULL;
3002         r_texture_fogheighttexture = NULL;
3003         r_texture_gammaramps = NULL;
3004         r_texture_numcubemaps = 0;
3005         r_uniformbufferalignment = 32;
3006
3007         r_loaddds = r_texture_dds_load.integer != 0;
3008         r_savedds = vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3009
3010         switch(vid.renderpath)
3011         {
3012         case RENDERPATH_GL32:
3013         case RENDERPATH_GLES2:
3014                 Cvar_SetValueQuick(&r_textureunits, MAX_TEXTUREUNITS);
3015                 Cvar_SetValueQuick(&gl_combine, 1);
3016                 Cvar_SetValueQuick(&r_glsl, 1);
3017                 r_loadnormalmap = true;
3018                 r_loadgloss = true;
3019                 r_loadfog = false;
3020 #ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
3021                 qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
3022 #endif
3023                 break;
3024         }
3025
3026         R_AnimCache_Free();
3027         R_FrameData_Reset();
3028         R_BufferData_Reset();
3029
3030         r_numqueries = 0;
3031         r_maxqueries = 0;
3032         memset(r_queries, 0, sizeof(r_queries));
3033
3034         r_qwskincache = NULL;
3035         r_qwskincache_size = 0;
3036
3037         // due to caching of texture_t references, the collision cache must be reset
3038         Collision_Cache_Reset(true);
3039
3040         // set up r_skinframe loading system for textures
3041         memset(&r_skinframe, 0, sizeof(r_skinframe));
3042         r_skinframe.loadsequence = 1;
3043         Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
3044
3045         r_main_texturepool = R_AllocTexturePool();
3046         R_BuildBlankTextures();
3047         R_BuildNoTexture();
3048         R_BuildWhiteCube();
3049         R_BuildNormalizationCube();
3050         r_texture_fogattenuation = NULL;
3051         r_texture_fogheighttexture = NULL;
3052         r_texture_gammaramps = NULL;
3053         //r_texture_fogintensity = NULL;
3054         memset(&r_fb, 0, sizeof(r_fb));
3055         Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
3056         r_glsl_permutation = NULL;
3057         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3058         Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
3059         memset(&r_svbsp, 0, sizeof (r_svbsp));
3060
3061         memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
3062         r_texture_numcubemaps = 0;
3063
3064         r_refdef.fogmasktable_density = 0;
3065
3066 #ifdef __ANDROID__
3067         // For Steelstorm Android
3068         // FIXME CACHE the program and reload
3069         // FIXME see possible combinations for SS:BR android
3070         Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
3071         R_SetupShader_SetPermutationGLSL(0, 12);
3072         R_SetupShader_SetPermutationGLSL(0, 13);
3073         R_SetupShader_SetPermutationGLSL(0, 8388621);
3074         R_SetupShader_SetPermutationGLSL(3, 0);
3075         R_SetupShader_SetPermutationGLSL(3, 2048);
3076         R_SetupShader_SetPermutationGLSL(5, 0);
3077         R_SetupShader_SetPermutationGLSL(5, 2);
3078         R_SetupShader_SetPermutationGLSL(5, 2048);
3079         R_SetupShader_SetPermutationGLSL(5, 8388608);
3080         R_SetupShader_SetPermutationGLSL(11, 1);
3081         R_SetupShader_SetPermutationGLSL(11, 2049);
3082         R_SetupShader_SetPermutationGLSL(11, 8193);
3083         R_SetupShader_SetPermutationGLSL(11, 10241);
3084         Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
3085 #endif
3086 }
3087
3088 extern unsigned int r_shadow_occlusion_buf;
3089
3090 static void gl_main_shutdown(void)
3091 {
3092         R_RenderTarget_FreeUnused(true);
3093         Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
3094         R_AnimCache_Free();
3095         R_FrameData_Reset();
3096         R_BufferData_Reset();
3097
3098         R_Main_FreeViewCache();
3099
3100         switch(vid.renderpath)
3101         {
3102         case RENDERPATH_GL32:
3103         case RENDERPATH_GLES2:
3104 #if defined(GL_SAMPLES_PASSED) && !defined(USE_GLES2)
3105                 if (r_maxqueries)
3106                         qglDeleteQueries(r_maxqueries, r_queries);
3107 #endif
3108                 break;
3109         }
3110         r_shadow_occlusion_buf = 0;
3111         r_numqueries = 0;
3112         r_maxqueries = 0;
3113         memset(r_queries, 0, sizeof(r_queries));
3114
3115         r_qwskincache = NULL;
3116         r_qwskincache_size = 0;
3117
3118         // clear out the r_skinframe state
3119         Mem_ExpandableArray_FreeArray(&r_skinframe.array);
3120         memset(&r_skinframe, 0, sizeof(r_skinframe));
3121
3122         if (r_svbsp.nodes)
3123                 Mem_Free(r_svbsp.nodes);
3124         memset(&r_svbsp, 0, sizeof (r_svbsp));
3125         R_FreeTexturePool(&r_main_texturepool);
3126         loadingscreentexture = NULL;
3127         r_texture_blanknormalmap = NULL;
3128         r_texture_white = NULL;
3129         r_texture_grey128 = NULL;
3130         r_texture_black = NULL;
3131         r_texture_whitecube = NULL;
3132         r_texture_normalizationcube = NULL;
3133         r_texture_fogattenuation = NULL;
3134         r_texture_fogheighttexture = NULL;
3135         r_texture_gammaramps = NULL;
3136         r_texture_numcubemaps = 0;
3137         //r_texture_fogintensity = NULL;
3138         memset(&r_fb, 0, sizeof(r_fb));
3139         R_GLSL_Restart_f(&cmd_client);
3140
3141         r_glsl_permutation = NULL;
3142         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3143         Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
3144 }
3145
3146 static void gl_main_newmap(void)
3147 {
3148         // FIXME: move this code to client
3149         char *entities, entname[MAX_QPATH];
3150         if (r_qwskincache)
3151                 Mem_Free(r_qwskincache);
3152         r_qwskincache = NULL;
3153         r_qwskincache_size = 0;
3154         if (cl.worldmodel)
3155         {
3156                 dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension);
3157                 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
3158                 {
3159                         CL_ParseEntityLump(entities);
3160                         Mem_Free(entities);
3161                         return;
3162                 }
3163                 if (cl.worldmodel->brush.entities)
3164                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
3165         }
3166         R_Main_FreeViewCache();
3167
3168         R_FrameData_Reset();
3169         R_BufferData_Reset();
3170 }
3171
3172 void GL_Main_Init(void)
3173 {
3174         int i;
3175         r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
3176         R_InitShaderModeInfo();
3177
3178         Cmd_AddCommand(&cmd_client, "r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
3179         Cmd_AddCommand(&cmd_client, "r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
3180         // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
3181         if (gamemode == GAME_NEHAHRA)
3182         {
3183                 Cvar_RegisterVariable (&gl_fogenable);
3184                 Cvar_RegisterVariable (&gl_fogdensity);
3185                 Cvar_RegisterVariable (&gl_fogred);
3186                 Cvar_RegisterVariable (&gl_foggreen);
3187                 Cvar_RegisterVariable (&gl_fogblue);
3188                 Cvar_RegisterVariable (&gl_fogstart);
3189                 Cvar_RegisterVariable (&gl_fogend);
3190                 Cvar_RegisterVariable (&gl_skyclip);
3191         }
3192         Cvar_RegisterVariable(&r_motionblur);
3193         Cvar_RegisterVariable(&r_damageblur);
3194         Cvar_RegisterVariable(&r_motionblur_averaging);
3195         Cvar_RegisterVariable(&r_motionblur_randomize);
3196         Cvar_RegisterVariable(&r_motionblur_minblur);
3197         Cvar_RegisterVariable(&r_motionblur_maxblur);
3198         Cvar_RegisterVariable(&r_motionblur_velocityfactor);
3199         Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed);
3200         Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed);
3201         Cvar_RegisterVariable(&r_motionblur_mousefactor);
3202         Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed);
3203         Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed);
3204         Cvar_RegisterVariable(&r_depthfirst);
3205         Cvar_RegisterVariable(&r_useinfinitefarclip);
3206         Cvar_RegisterVariable(&r_farclip_base);
3207         Cvar_RegisterVariable(&r_farclip_world);
3208         Cvar_RegisterVariable(&r_nearclip);
3209         Cvar_RegisterVariable(&r_deformvertexes);
3210         Cvar_RegisterVariable(&r_transparent);
3211         Cvar_RegisterVariable(&r_transparent_alphatocoverage);
3212         Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
3213         Cvar_RegisterVariable(&r_transparent_useplanardistance);
3214         Cvar_RegisterVariable(&r_showoverdraw);
3215         Cvar_RegisterVariable(&r_showbboxes);
3216         Cvar_RegisterVariable(&r_showbboxes_client);
3217         Cvar_RegisterVariable(&r_showsurfaces);
3218         Cvar_RegisterVariable(&r_showtris);
3219         Cvar_RegisterVariable(&r_shownormals);
3220         Cvar_RegisterVariable(&r_showlighting);
3221         Cvar_RegisterVariable(&r_showcollisionbrushes);
3222         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
3223         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
3224         Cvar_RegisterVariable(&r_showdisabledepthtest);
3225         Cvar_RegisterVariable(&r_showspriteedges);
3226         Cvar_RegisterVariable(&r_showparticleedges);
3227         Cvar_RegisterVariable(&r_drawportals);
3228         Cvar_RegisterVariable(&r_drawentities);
3229         Cvar_RegisterVariable(&r_draw2d);
3230         Cvar_RegisterVariable(&r_drawworld);
3231         Cvar_RegisterVariable(&r_cullentities_trace);
3232         Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
3233         Cvar_RegisterVariable(&r_cullentities_trace_samples);
3234         Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
3235         Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
3236         Cvar_RegisterVariable(&r_cullentities_trace_expand);
3237         Cvar_RegisterVariable(&r_cullentities_trace_pad);
3238         Cvar_RegisterVariable(&r_cullentities_trace_delay);
3239         Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
3240         Cvar_RegisterVariable(&r_sortentities);
3241         Cvar_RegisterVariable(&r_drawviewmodel);
3242         Cvar_RegisterVariable(&r_drawexteriormodel);
3243         Cvar_RegisterVariable(&r_speeds);
3244         Cvar_RegisterVariable(&r_fullbrights);
3245         Cvar_RegisterVariable(&r_wateralpha);
3246         Cvar_RegisterVariable(&r_dynamic);
3247         Cvar_RegisterVariable(&r_fullbright_directed);
3248         Cvar_RegisterVariable(&r_fullbright_directed_ambient);
3249         Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
3250         Cvar_RegisterVariable(&r_fullbright_directed_pitch);
3251         Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
3252         Cvar_RegisterVariable(&r_fullbright);
3253         Cvar_RegisterVariable(&r_shadows);
3254         Cvar_RegisterVariable(&r_shadows_darken);
3255         Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
3256         Cvar_RegisterVariable(&r_shadows_castfrombmodels);
3257         Cvar_RegisterVariable(&r_shadows_throwdistance);
3258         Cvar_RegisterVariable(&r_shadows_throwdirection);
3259         Cvar_RegisterVariable(&r_shadows_focus);
3260         Cvar_RegisterVariable(&r_shadows_shadowmapscale);
3261         Cvar_RegisterVariable(&r_shadows_shadowmapbias);
3262         Cvar_RegisterVariable(&r_q1bsp_skymasking);
3263         Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
3264         Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
3265         Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
3266         Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
3267         Cvar_RegisterVariable(&r_fog_exp2);
3268         Cvar_RegisterVariable(&r_fog_clear);
3269         Cvar_RegisterVariable(&r_drawfog);
3270         Cvar_RegisterVariable(&r_transparentdepthmasking);
3271         Cvar_RegisterVariable(&r_transparent_sortmindist);
3272         Cvar_RegisterVariable(&r_transparent_sortmaxdist);
3273         Cvar_RegisterVariable(&r_transparent_sortarraysize);
3274         Cvar_RegisterVariable(&r_texture_dds_load);
3275         Cvar_RegisterVariable(&r_texture_dds_save);
3276         Cvar_RegisterVariable(&r_textureunits);
3277         Cvar_RegisterVariable(&gl_combine);
3278         Cvar_RegisterVariable(&r_usedepthtextures);
3279         Cvar_RegisterVariable(&r_viewfbo);
3280         Cvar_RegisterVariable(&r_rendertarget_debug);
3281         Cvar_RegisterVariable(&r_viewscale);
3282         Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3283         Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3284         Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3285         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3286         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3287         Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3288         Cvar_RegisterVariable(&r_glsl);
3289         Cvar_RegisterVariable(&r_glsl_deluxemapping);
3290         Cvar_RegisterVariable(&r_glsl_offsetmapping);
3291         Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3292         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3293         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3294         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3295         Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3296         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3297         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3298         Cvar_RegisterVariable(&r_glsl_postprocess);
3299         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3300         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3301         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3302         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3303         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3304         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3305         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3306         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3307         Cvar_RegisterVariable(&r_celshading);
3308         Cvar_RegisterVariable(&r_celoutlines);
3309
3310         Cvar_RegisterVariable(&r_water);
3311         Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3312         Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3313         Cvar_RegisterVariable(&r_water_clippingplanebias);
3314         Cvar_RegisterVariable(&r_water_refractdistort);
3315         Cvar_RegisterVariable(&r_water_reflectdistort);
3316         Cvar_RegisterVariable(&r_water_scissormode);
3317         Cvar_RegisterVariable(&r_water_lowquality);
3318         Cvar_RegisterVariable(&r_water_hideplayer);
3319
3320         Cvar_RegisterVariable(&r_lerpsprites);
3321         Cvar_RegisterVariable(&r_lerpmodels);
3322         Cvar_RegisterVariable(&r_lerplightstyles);
3323         Cvar_RegisterVariable(&r_waterscroll);
3324         Cvar_RegisterVariable(&r_bloom);
3325         Cvar_RegisterVariable(&r_colorfringe);
3326         Cvar_RegisterVariable(&r_bloom_colorscale);
3327         Cvar_RegisterVariable(&r_bloom_brighten);
3328         Cvar_RegisterVariable(&r_bloom_blur);
3329         Cvar_RegisterVariable(&r_bloom_resolution);
3330         Cvar_RegisterVariable(&r_bloom_colorexponent);
3331         Cvar_RegisterVariable(&r_bloom_colorsubtract);
3332         Cvar_RegisterVariable(&r_bloom_scenebrightness);
3333         Cvar_RegisterVariable(&r_hdr_scenebrightness);
3334         Cvar_RegisterVariable(&r_hdr_glowintensity);
3335         Cvar_RegisterVariable(&r_hdr_irisadaptation);
3336         Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3337         Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3338         Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3339         Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3340         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3341         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3342         Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3343         Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3344         Cvar_RegisterVariable(&developer_texturelogging);
3345         Cvar_RegisterVariable(&gl_lightmaps);
3346         Cvar_RegisterVariable(&r_test);
3347         Cvar_RegisterVariable(&r_batch_multidraw);
3348         Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3349         Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3350         Cvar_RegisterVariable(&r_glsl_skeletal);
3351         Cvar_RegisterVariable(&r_glsl_saturation);
3352         Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3353         Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3354         Cvar_RegisterVariable(&r_framedatasize);
3355         for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3356                 Cvar_RegisterVariable(&r_buffermegs[i]);
3357         Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3358         if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3359                 Cvar_SetValue(&cvars_all, "r_fullbrights", 0);
3360 #ifdef DP_MOBILETOUCH
3361         // GLES devices have terrible depth precision in general, so...
3362         Cvar_SetValueQuick(&r_nearclip, 4);
3363         Cvar_SetValueQuick(&r_farclip_base, 4096);
3364         Cvar_SetValueQuick(&r_farclip_world, 0);
3365         Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3366 #endif
3367         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3368 }
3369
3370 void Render_Init(void)
3371 {
3372         gl_backend_init();
3373         R_Textures_Init();
3374         GL_Main_Init();
3375         Font_Init();
3376         GL_Draw_Init();
3377         R_Shadow_Init();
3378         R_Sky_Init();
3379         GL_Surf_Init();
3380         Sbar_Init();
3381         R_Particles_Init();
3382         R_Explosion_Init();
3383         R_LightningBeams_Init();
3384         Mod_RenderInit();
3385 }
3386
3387 int R_CullBox(const vec3_t mins, const vec3_t maxs)
3388 {
3389         int i;
3390         mplane_t *p;
3391         if (r_trippy.integer)
3392                 return false;
3393         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
3394         {
3395                 p = r_refdef.view.frustum + i;
3396                 switch(p->signbits)
3397                 {
3398                 default:
3399                 case 0:
3400                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3401                                 return true;
3402                         break;
3403                 case 1:
3404                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3405                                 return true;
3406                         break;
3407                 case 2:
3408                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3409                                 return true;
3410                         break;
3411                 case 3:
3412                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3413                                 return true;
3414                         break;
3415                 case 4:
3416                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3417                                 return true;
3418                         break;
3419                 case 5:
3420                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3421                                 return true;
3422                         break;
3423                 case 6:
3424                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3425                                 return true;
3426                         break;
3427                 case 7:
3428                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3429                                 return true;
3430                         break;
3431                 }
3432         }
3433         return false;
3434 }
3435
3436 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3437 {
3438         int i;
3439         const mplane_t *p;
3440         if (r_trippy.integer)
3441                 return false;
3442         for (i = 0;i < numplanes;i++)
3443         {
3444                 p = planes + i;
3445                 switch(p->signbits)
3446                 {
3447                 default:
3448                 case 0:
3449                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3450                                 return true;
3451                         break;
3452                 case 1:
3453                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3454                                 return true;
3455                         break;
3456                 case 2:
3457                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3458                                 return true;
3459                         break;
3460                 case 3:
3461                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3462                                 return true;
3463                         break;
3464                 case 4:
3465                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3466                                 return true;
3467                         break;
3468                 case 5:
3469                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3470                                 return true;
3471                         break;
3472                 case 6:
3473                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3474                                 return true;
3475                         break;
3476                 case 7:
3477                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3478                                 return true;
3479                         break;
3480                 }
3481         }
3482         return false;
3483 }
3484
3485 //==================================================================================
3486
3487 // LadyHavoc: this stores temporary data used within the same frame
3488
3489 typedef struct r_framedata_mem_s
3490 {
3491         struct r_framedata_mem_s *purge; // older mem block to free on next frame
3492         size_t size; // how much usable space
3493         size_t current; // how much space in use
3494         size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3495         size_t wantedsize; // how much space was allocated
3496         unsigned char *data; // start of real data (16byte aligned)
3497 }
3498 r_framedata_mem_t;
3499
3500 static r_framedata_mem_t *r_framedata_mem;
3501
3502 void R_FrameData_Reset(void)
3503 {
3504         while (r_framedata_mem)
3505         {
3506                 r_framedata_mem_t *next = r_framedata_mem->purge;
3507                 Mem_Free(r_framedata_mem);
3508                 r_framedata_mem = next;
3509         }
3510 }
3511
3512 static void R_FrameData_Resize(qboolean mustgrow)
3513 {
3514         size_t wantedsize;
3515         wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3516         wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3517         if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3518         {
3519                 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3520                 newmem->wantedsize = wantedsize;
3521                 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3522                 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3523                 newmem->current = 0;
3524                 newmem->mark = 0;
3525                 newmem->purge = r_framedata_mem;
3526                 r_framedata_mem = newmem;
3527         }
3528 }
3529
3530 void R_FrameData_NewFrame(void)
3531 {
3532         R_FrameData_Resize(false);
3533         if (!r_framedata_mem)
3534                 return;
3535         // if we ran out of space on the last frame, free the old memory now
3536         while (r_framedata_mem->purge)
3537         {
3538                 // repeatedly remove the second item in the list, leaving only head
3539                 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3540                 Mem_Free(r_framedata_mem->purge);
3541                 r_framedata_mem->purge = next;
3542         }
3543         // reset the current mem pointer
3544         r_framedata_mem->current = 0;
3545         r_framedata_mem->mark = 0;
3546 }
3547
3548 void *R_FrameData_Alloc(size_t size)
3549 {
3550         void *data;
3551         float newvalue;
3552
3553         // align to 16 byte boundary - the data pointer is already aligned, so we
3554         // only need to ensure the size of every allocation is also aligned
3555         size = (size + 15) & ~15;
3556
3557         while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3558         {
3559                 // emergency - we ran out of space, allocate more memory
3560                 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3561                 newvalue = r_framedatasize.value * 2.0f;
3562                 // upper bound based on architecture - if we try to allocate more than this we could overflow, better to loop until we error out on allocation failure
3563                 if (sizeof(size_t) >= 8)
3564                         newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3565                 else
3566                         newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3567                 // this might not be a growing it, but we'll allocate another buffer every time
3568                 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3569                 R_FrameData_Resize(true);
3570         }
3571
3572         data = r_framedata_mem->data + r_framedata_mem->current;
3573         r_framedata_mem->current += size;
3574
3575         // count the usage for stats
3576         r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3577         r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3578
3579         return (void *)data;
3580 }
3581
3582 void *R_FrameData_Store(size_t size, void *data)
3583 {
3584         void *d = R_FrameData_Alloc(size);
3585         if (d && data)
3586                 memcpy(d, data, size);
3587         return d;
3588 }
3589
3590 void R_FrameData_SetMark(void)
3591 {
3592         if (!r_framedata_mem)
3593                 return;
3594         r_framedata_mem->mark = r_framedata_mem->current;
3595 }
3596
3597 void R_FrameData_ReturnToMark(void)
3598 {
3599         if (!r_framedata_mem)
3600                 return;
3601         r_framedata_mem->current = r_framedata_mem->mark;
3602 }
3603
3604 //==================================================================================
3605
3606 // avoid reusing the same buffer objects on consecutive frames
3607 #define R_BUFFERDATA_CYCLE 3
3608
3609 typedef struct r_bufferdata_buffer_s
3610 {
3611         struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3612         size_t size; // how much usable space
3613         size_t current; // how much space in use
3614         r_meshbuffer_t *buffer; // the buffer itself
3615 }
3616 r_bufferdata_buffer_t;
3617
3618 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3619 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3620
3621 /// frees all dynamic buffers
3622 void R_BufferData_Reset(void)
3623 {
3624         int cycle, type;
3625         r_bufferdata_buffer_t **p, *mem;
3626         for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3627         {
3628                 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3629                 {
3630                         // free all buffers
3631                         p = &r_bufferdata_buffer[cycle][type];
3632                         while (*p)
3633                         {
3634                                 mem = *p;
3635                                 *p = (*p)->purge;
3636                                 if (mem->buffer)
3637                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3638                                 Mem_Free(mem);
3639                         }
3640                 }
3641         }
3642 }
3643
3644 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3645 static void R_BufferData_Resize(r_bufferdata_type_t type, qboolean mustgrow, size_t minsize)
3646 {
3647         r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3648         size_t size;
3649         float newvalue = r_buffermegs[type].value;
3650
3651         // increase the cvar if we have to (but only if we already have a mem)
3652         if (mustgrow && mem)
3653                 newvalue *= 2.0f;
3654         newvalue = bound(0.25f, newvalue, 256.0f);
3655         while (newvalue * 1024*1024 < minsize)
3656                 newvalue *= 2.0f;
3657
3658         // clamp the cvar to valid range
3659         newvalue = bound(0.25f, newvalue, 256.0f);
3660         if (r_buffermegs[type].value != newvalue)
3661                 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3662
3663         // calculate size in bytes
3664         size = (size_t)(newvalue * 1024*1024);
3665         size = bound(131072, size, 256*1024*1024);
3666
3667         // allocate a new buffer if the size is different (purge old one later)
3668         // or if we were told we must grow the buffer
3669         if (!mem || mem->size != size || mustgrow)
3670         {
3671                 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3672                 mem->size = size;
3673                 mem->current = 0;
3674                 if (type == R_BUFFERDATA_VERTEX)
3675                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3676                 else if (type == R_BUFFERDATA_INDEX16)
3677                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3678                 else if (type == R_BUFFERDATA_INDEX32)
3679                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3680                 else if (type == R_BUFFERDATA_UNIFORM)
3681                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3682                 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3683                 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3684         }
3685 }
3686
3687 void R_BufferData_NewFrame(void)
3688 {
3689         int type;
3690         r_bufferdata_buffer_t **p, *mem;
3691         // cycle to the next frame's buffers
3692         r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3693         // if we ran out of space on the last time we used these buffers, free the old memory now
3694         for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3695         {
3696                 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3697                 {
3698                         R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3699                         // free all but the head buffer, this is how we recycle obsolete
3700                         // buffers after they are no longer in use
3701                         p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3702                         while (*p)
3703                         {
3704                                 mem = *p;
3705                                 *p = (*p)->purge;
3706                                 if (mem->buffer)
3707                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3708                                 Mem_Free(mem);
3709                         }
3710                         // reset the current offset
3711                         r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3712                 }
3713         }
3714 }
3715
3716 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3717 {
3718         r_bufferdata_buffer_t *mem;
3719         int offset = 0;
3720         int padsize;
3721
3722         *returnbufferoffset = 0;
3723
3724         // align size to a byte boundary appropriate for the buffer type, this
3725         // makes all allocations have aligned start offsets
3726         if (type == R_BUFFERDATA_UNIFORM)
3727                 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3728         else
3729                 padsize = (datasize + 15) & ~15;
3730
3731         // if we ran out of space in this buffer we must allocate a new one
3732         if (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size)
3733                 R_BufferData_Resize(type, true, padsize);
3734
3735         // if the resize did not give us enough memory, fail
3736         if (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size)
3737                 Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3738
3739         mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3740         offset = (int)mem->current;
3741         mem->current += padsize;
3742
3743         // upload the data to the buffer at the chosen offset
3744         if (offset == 0)
3745                 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3746         R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3747
3748         // count the usage for stats
3749         r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3750         r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3751
3752         // return the buffer offset
3753         *returnbufferoffset = offset;
3754
3755         return mem->buffer;
3756 }
3757
3758 //==================================================================================
3759
3760 // LadyHavoc: animcache originally written by Echon, rewritten since then
3761
3762 /**
3763  * Animation cache prevents re-generating mesh data for an animated model
3764  * multiple times in one frame for lighting, shadowing, reflections, etc.
3765  */
3766
3767 void R_AnimCache_Free(void)
3768 {
3769 }
3770
3771 void R_AnimCache_ClearCache(void)
3772 {
3773         int i;
3774         entity_render_t *ent;
3775
3776         for (i = 0;i < r_refdef.scene.numentities;i++)
3777         {
3778                 ent = r_refdef.scene.entities[i];
3779                 ent->animcache_vertex3f = NULL;
3780                 ent->animcache_vertex3f_vertexbuffer = NULL;
3781                 ent->animcache_vertex3f_bufferoffset = 0;
3782                 ent->animcache_normal3f = NULL;
3783                 ent->animcache_normal3f_vertexbuffer = NULL;
3784                 ent->animcache_normal3f_bufferoffset = 0;
3785                 ent->animcache_svector3f = NULL;
3786                 ent->animcache_svector3f_vertexbuffer = NULL;
3787                 ent->animcache_svector3f_bufferoffset = 0;
3788                 ent->animcache_tvector3f = NULL;
3789                 ent->animcache_tvector3f_vertexbuffer = NULL;
3790                 ent->animcache_tvector3f_bufferoffset = 0;
3791                 ent->animcache_skeletaltransform3x4 = NULL;
3792                 ent->animcache_skeletaltransform3x4buffer = NULL;
3793                 ent->animcache_skeletaltransform3x4offset = 0;
3794                 ent->animcache_skeletaltransform3x4size = 0;
3795         }
3796 }
3797
3798 qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
3799 {
3800         dp_model_t *model = ent->model;
3801         int numvertices;
3802
3803         // see if this ent is worth caching
3804         if (!model || !model->Draw || !model->AnimateVertices)
3805                 return false;
3806         // nothing to cache if it contains no animations and has no skeleton
3807         if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3808                 return false;
3809         // see if it is already cached for gpuskeletal
3810         if (ent->animcache_skeletaltransform3x4)
3811                 return false;
3812         // see if it is already cached as a mesh
3813         if (ent->animcache_vertex3f)
3814         {
3815                 // check if we need to add normals or tangents
3816                 if (ent->animcache_normal3f)
3817                         wantnormals = false;
3818                 if (ent->animcache_svector3f)
3819                         wanttangents = false;
3820                 if (!wantnormals && !wanttangents)
3821                         return false;
3822         }
3823
3824         // check which kind of cache we need to generate
3825         if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3826         {
3827                 // cache the skeleton so the vertex shader can use it
3828                 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3829                 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3830                 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3831                 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3832                 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4); 
3833                 // note: this can fail if the buffer is at the grow limit
3834                 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3835                 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3836         }
3837         else if (ent->animcache_vertex3f)
3838         {
3839                 // mesh was already cached but we may need to add normals/tangents
3840                 // (this only happens with multiple views, reflections, cameras, etc)
3841                 if (wantnormals || wanttangents)
3842                 {
3843                         numvertices = model->surfmesh.num_vertices;
3844                         if (wantnormals)
3845                                 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3846                         if (wanttangents)
3847                         {
3848                                 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3849                                 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3850                         }
3851                         model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3852                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3853                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3854                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3855                 }
3856         }
3857         else
3858         {
3859                 // generate mesh cache
3860                 numvertices = model->surfmesh.num_vertices;
3861                 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3862                 if (wantnormals)
3863                         ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3864                 if (wanttangents)
3865                 {
3866                         ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3867                         ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3868                 }
3869                 model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
3870                 if (wantnormals || wanttangents)
3871                 {
3872                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3873                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3874                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3875                 }
3876                 r_refdef.stats[r_stat_animcache_shape_count] += 1;
3877                 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
3878                 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
3879         }
3880         return true;
3881 }
3882
3883 void R_AnimCache_CacheVisibleEntities(void)
3884 {
3885         int i;
3886
3887         // TODO: thread this
3888         // NOTE: R_PrepareRTLights() also caches entities
3889
3890         for (i = 0;i < r_refdef.scene.numentities;i++)
3891                 if (r_refdef.viewcache.entityvisible[i])
3892                         R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
3893 }
3894
3895 //==================================================================================
3896
3897 qboolean R_CanSeeBox(int numsamples, vec_t eyejitter, vec_t entboxenlarge, vec_t entboxexpand, vec_t pad, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs)
3898 {
3899         int i;
3900         vec3_t eyemins, eyemaxs;
3901         vec3_t boxmins, boxmaxs;
3902         vec3_t padmins, padmaxs;
3903         vec3_t start;
3904         vec3_t end;
3905         dp_model_t *model = r_refdef.scene.worldmodel;
3906         static vec3_t positions[] = {
3907                 { 0.5f, 0.5f, 0.5f },
3908                 { 0.0f, 0.0f, 0.0f },
3909                 { 0.0f, 0.0f, 1.0f },
3910                 { 0.0f, 1.0f, 0.0f },
3911                 { 0.0f, 1.0f, 1.0f },
3912                 { 1.0f, 0.0f, 0.0f },
3913                 { 1.0f, 0.0f, 1.0f },
3914                 { 1.0f, 1.0f, 0.0f },
3915                 { 1.0f, 1.0f, 1.0f },
3916         };
3917
3918         // sample count can be set to -1 to skip this logic, for flicker-prone objects
3919         if (numsamples < 0)
3920                 return true;
3921
3922         // view origin is not used for culling in portal/reflection/refraction renders or isometric views
3923         if (!r_refdef.view.usevieworiginculling)
3924                 return true;
3925
3926         if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
3927                 return true;
3928
3929         // expand the eye box a little
3930         eyemins[0] = eye[0] - eyejitter;
3931         eyemaxs[0] = eye[0] + eyejitter;
3932         eyemins[1] = eye[1] - eyejitter;
3933         eyemaxs[1] = eye[1] + eyejitter;
3934         eyemins[2] = eye[2] - eyejitter;
3935         eyemaxs[2] = eye[2] + eyejitter;
3936         // expand the box a little
3937         boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
3938         boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
3939         boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
3940         boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
3941         boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
3942         boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
3943         // make an even larger box for the acceptable area
3944         padmins[0] = boxmins[0] - pad;
3945         padmaxs[0] = boxmaxs[0] + pad;
3946         padmins[1] = boxmins[1] - pad;
3947         padmaxs[1] = boxmaxs[1] + pad;
3948         padmins[2] = boxmins[2] - pad;
3949         padmaxs[2] = boxmaxs[2] + pad;
3950
3951         // return true if eye overlaps enlarged box
3952         if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
3953                 return true;
3954
3955         // try specific positions in the box first - note that these can be cached
3956         if (r_cullentities_trace_entityocclusion.integer)
3957         {
3958                 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
3959                 {
3960                         VectorCopy(eye, start);
3961                         end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
3962                         end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
3963                         end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
3964                         //trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
3965                         trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
3966                         // not picky - if the trace ended anywhere in the box we're good
3967                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
3968                                 return true;
3969                 }
3970         }
3971         else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
3972                 return true;
3973
3974         // try various random positions
3975         for (i = 0; i < numsamples; i++)
3976         {
3977                 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
3978                 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
3979                 if (r_cullentities_trace_entityocclusion.integer)
3980                 {
3981                         trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
3982                         // not picky - if the trace ended anywhere in the box we're good
3983                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
3984                                 return true;
3985                 }
3986                 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
3987                         return true;
3988         }
3989
3990         return false;
3991 }
3992
3993
3994 static void R_View_UpdateEntityVisible (void)
3995 {
3996         int i;
3997         int renderimask;
3998         int samples;
3999         entity_render_t *ent;
4000
4001         if (r_refdef.envmap || r_fb.water.hideplayer)
4002                 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
4003         else if (chase_active.integer || r_fb.water.renderingscene)
4004                 renderimask = RENDER_VIEWMODEL;
4005         else
4006                 renderimask = RENDER_EXTERIORMODEL;
4007         if (!r_drawviewmodel.integer)
4008                 renderimask |= RENDER_VIEWMODEL;
4009         if (!r_drawexteriormodel.integer)
4010                 renderimask |= RENDER_EXTERIORMODEL;
4011         memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4012         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4013         {
4014                 // worldmodel can check visibility
4015                 for (i = 0;i < r_refdef.scene.numentities;i++)
4016                 {
4017                         ent = r_refdef.scene.entities[i];
4018                         if (!(ent->flags & renderimask))
4019                         if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
4020                         if ((ent->flags & (RENDER_NODEPTHTEST | RENDER_WORLDOBJECT | RENDER_VIEWMODEL)) || r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, ent->mins, ent->maxs))
4021                                 r_refdef.viewcache.entityvisible[i] = true;
4022                 }
4023         }
4024         else
4025         {
4026                 // no worldmodel or it can't check visibility
4027                 for (i = 0;i < r_refdef.scene.numentities;i++)
4028                 {
4029                         ent = r_refdef.scene.entities[i];
4030                         if (!(ent->flags & renderimask))
4031                         if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
4032                                 r_refdef.viewcache.entityvisible[i] = true;
4033                 }
4034         }
4035         if (r_cullentities_trace.integer)
4036         {
4037                 for (i = 0;i < r_refdef.scene.numentities;i++)
4038                 {
4039                         if (!r_refdef.viewcache.entityvisible[i])
4040                                 continue;
4041                         ent = r_refdef.scene.entities[i];
4042                         if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4043                         {
4044                                 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4045                                 if (R_CanSeeBox(samples, r_cullentities_trace_eyejitter.value, r_cullentities_trace_enlarge.value, r_cullentities_trace_expand.value, r_cullentities_trace_pad.value, r_refdef.view.origin, ent->mins, ent->maxs))
4046                                         ent->last_trace_visibility = realtime;
4047                                 if (ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
4048                                         r_refdef.viewcache.entityvisible[i] = 0;
4049                         }
4050                 }
4051         }
4052 }
4053
4054 /// only used if skyrendermasked, and normally returns false
4055 static int R_DrawBrushModelsSky (void)
4056 {
4057         int i, sky;
4058         entity_render_t *ent;
4059
4060         sky = false;
4061         for (i = 0;i < r_refdef.scene.numentities;i++)
4062         {
4063                 if (!r_refdef.viewcache.entityvisible[i])
4064                         continue;
4065                 ent = r_refdef.scene.entities[i];
4066                 if (!ent->model || !ent->model->DrawSky)
4067                         continue;
4068                 ent->model->DrawSky(ent);
4069                 sky = true;
4070         }
4071         return sky;
4072 }
4073
4074 static void R_DrawNoModel(entity_render_t *ent);
4075 static void R_DrawModels(void)
4076 {
4077         int i;
4078         entity_render_t *ent;
4079
4080         for (i = 0;i < r_refdef.scene.numentities;i++)
4081         {
4082                 if (!r_refdef.viewcache.entityvisible[i])
4083                         continue;
4084                 ent = r_refdef.scene.entities[i];
4085                 r_refdef.stats[r_stat_entities]++;
4086                 /*
4087                 if (ent->model && !strncmp(ent->model->name, "models/proto_", 13))
4088                 {
4089                         vec3_t f, l, u, o;
4090                         Matrix4x4_ToVectors(&ent->matrix, f, l, u, o);
4091                         Con_Printf("R_DrawModels\n");
4092                         Con_Printf("model %s O %f %f %f F %f %f %f L %f %f %f U %f %f %f\n", ent->model->name, o[0], o[1], o[2], f[0], f[1], f[2], l[0], l[1], l[2], u[0], u[1], u[2]);
4093                         Con_Printf("group: %i %f %i %f %i %f %i %f\n", ent->framegroupblend[0].frame, ent->framegroupblend[0].lerp, ent->framegroupblend[1].frame, ent->framegroupblend[1].lerp, ent->framegroupblend[2].frame, ent->framegroupblend[2].lerp, ent->framegroupblend[3].frame, ent->framegroupblend[3].lerp);
4094                         Con_Printf("blend: %i %f %i %f %i %f %i %f %i %f %i %f %i %f %i %f\n", ent->frameblend[0].subframe, ent->frameblend[0].lerp, ent->frameblend[1].subframe, ent->frameblend[1].lerp, ent->frameblend[2].subframe, ent->frameblend[2].lerp, ent->frameblend[3].subframe, ent->frameblend[3].lerp, ent->frameblend[4].subframe, ent->frameblend[4].lerp, ent->frameblend[5].subframe, ent->frameblend[5].lerp, ent->frameblend[6].subframe, ent->frameblend[6].lerp, ent->frameblend[7].subframe, ent->frameblend[7].lerp);
4095                 }
4096                 */
4097                 if (ent->model && ent->model->Draw != NULL)
4098                         ent->model->Draw(ent);
4099                 else
4100                         R_DrawNoModel(ent);
4101         }
4102 }
4103
4104 static void R_DrawModelsDepth(void)
4105 {
4106         int i;
4107         entity_render_t *ent;
4108
4109         for (i = 0;i < r_refdef.scene.numentities;i++)
4110         {
4111                 if (!r_refdef.viewcache.entityvisible[i])
4112                         continue;
4113                 ent = r_refdef.scene.entities[i];
4114                 if (ent->model && ent->model->DrawDepth != NULL)
4115                         ent->model->DrawDepth(ent);
4116         }
4117 }
4118
4119 static void R_DrawModelsDebug(void)
4120 {
4121         int i;
4122         entity_render_t *ent;
4123
4124         for (i = 0;i < r_refdef.scene.numentities;i++)
4125         {
4126                 if (!r_refdef.viewcache.entityvisible[i])
4127                         continue;
4128                 ent = r_refdef.scene.entities[i];
4129                 if (ent->model && ent->model->DrawDebug != NULL)
4130                         ent->model->DrawDebug(ent);
4131         }
4132 }
4133
4134 static void R_DrawModelsAddWaterPlanes(void)
4135 {
4136         int i;
4137         entity_render_t *ent;
4138
4139         for (i = 0;i < r_refdef.scene.numentities;i++)
4140         {
4141                 if (!r_refdef.viewcache.entityvisible[i])
4142                         continue;
4143                 ent = r_refdef.scene.entities[i];
4144                 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4145                         ent->model->DrawAddWaterPlanes(ent);
4146         }
4147 }
4148
4149 static float irisvecs[7][3] = {{0, 0, 0}, {-1, 0, 0}, {1, 0, 0}, {0, -1, 0}, {0, 1, 0}, {0, 0, -1}, {0, 0, 1}};
4150
4151 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4152 {
4153         if (r_hdr_irisadaptation.integer)
4154         {
4155                 vec3_t p;
4156                 vec3_t ambient;
4157                 vec3_t diffuse;
4158                 vec3_t diffusenormal;
4159                 vec3_t forward;
4160                 vec_t brightness = 0.0f;
4161                 vec_t goal;
4162                 vec_t current;
4163                 vec_t d;
4164                 int c;
4165                 VectorCopy(r_refdef.view.forward, forward);
4166                 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4167                 {
4168                         p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4169                         p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4170                         p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4171                         R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4172                         d = DotProduct(forward, diffusenormal);
4173                         brightness += VectorLength(ambient);
4174                         if (d > 0)
4175                                 brightness += d * VectorLength(diffuse);
4176                 }
4177                 brightness *= 1.0f / c;
4178                 brightness += 0.00001f; // make sure it's never zero
4179                 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4180                 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4181                 current = r_hdr_irisadaptation_value.value;
4182                 if (current < goal)
4183                         current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4184                 else if (current > goal)
4185                         current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4186                 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4187                         Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4188         }
4189         else if (r_hdr_irisadaptation_value.value != 1.0f)
4190                 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4191 }
4192
4193 static void R_View_SetFrustum(const int *scissor)
4194 {
4195         int i;
4196         double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4197         vec3_t forward, left, up, origin, v;
4198
4199         if(scissor)
4200         {
4201                 // flipped x coordinates (because x points left here)
4202                 fpx =  1.0 - 2.0 * (scissor[0]              - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4203                 fnx =  1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4204                 // non-flipped y coordinates
4205                 fny = -1.0 + 2.0 * (scissor[1]              - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4206                 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4207         }
4208
4209         // we can't trust r_refdef.view.forward and friends in reflected scenes
4210         Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4211
4212 #if 0
4213         r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4214         r_refdef.view.frustum[0].normal[1] = 0 - 0;
4215         r_refdef.view.frustum[0].normal[2] = -1 - 0;
4216         r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4217         r_refdef.view.frustum[1].normal[1] = 0 + 0;
4218         r_refdef.view.frustum[1].normal[2] = -1 + 0;
4219         r_refdef.view.frustum[2].normal[0] = 0 - 0;
4220         r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4221         r_refdef.view.frustum[2].normal[2] = -1 - 0;
4222         r_refdef.view.frustum[3].normal[0] = 0 + 0;
4223         r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4224         r_refdef.view.frustum[3].normal[2] = -1 + 0;
4225 #endif
4226
4227 #if 0
4228         zNear = r_refdef.nearclip;
4229         nudge = 1.0 - 1.0 / (1<<23);
4230         r_refdef.view.frustum[4].normal[0] = 0 - 0;
4231         r_refdef.view.frustum[4].normal[1] = 0 - 0;
4232         r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4233         r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4234         r_refdef.view.frustum[5].normal[0] = 0 + 0;
4235         r_refdef.view.frustum[5].normal[1] = 0 + 0;
4236         r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4237         r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4238 #endif
4239
4240
4241
4242 #if 0
4243         r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4244         r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4245         r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4246         r_refdef.view.frustum[0].dist = m[15] - m[12];
4247
4248         r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4249         r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4250         r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4251         r_refdef.view.frustum[1].dist = m[15] + m[12];
4252
4253         r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4254         r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4255         r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4256         r_refdef.view.frustum[2].dist = m[15] - m[13];
4257
4258         r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4259         r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4260         r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4261         r_refdef.view.frustum[3].dist = m[15] + m[13];
4262
4263         r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4264         r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4265         r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4266         r_refdef.view.frustum[4].dist = m[15] - m[14];
4267
4268         r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4269         r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4270         r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4271         r_refdef.view.frustum[5].dist = m[15] + m[14];
4272 #endif
4273
4274         if (r_refdef.view.useperspective)
4275         {
4276                 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4277                 VectorMAMAM(1024, forward, fnx * 1024.0 * r_refdef.view.frustum_x, left, fny * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[0]);
4278                 VectorMAMAM(1024, forward, fpx * 1024.0 * r_refdef.view.frustum_x, left, fny * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[1]);
4279                 VectorMAMAM(1024, forward, fnx * 1024.0 * r_refdef.view.frustum_x, left, fpy * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[2]);
4280                 VectorMAMAM(1024, forward, fpx * 1024.0 * r_refdef.view.frustum_x, left, fpy * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[3]);
4281
4282                 // then the normals from the corners relative to origin
4283                 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4284                 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4285                 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4286                 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4287
4288                 // in a NORMAL view, forward cross left == up
4289                 // in a REFLECTED view, forward cross left == down
4290                 // so our cross products above need to be adjusted for a left handed coordinate system
4291                 CrossProduct(forward, left, v);
4292                 if(DotProduct(v, up) < 0)
4293                 {
4294                         VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4295                         VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4296                         VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4297                         VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4298                 }
4299
4300                 // Leaving those out was a mistake, those were in the old code, and they
4301                 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4302                 // I couldn't reproduce it after adding those normalizations. --blub
4303                 VectorNormalize(r_refdef.view.frustum[0].normal);
4304                 VectorNormalize(r_refdef.view.frustum[1].normal);
4305                 VectorNormalize(r_refdef.view.frustum[2].normal);
4306                 VectorNormalize(r_refdef.view.frustum[3].normal);
4307
4308                 // make the corners absolute
4309                 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4310                 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4311                 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4312                 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4313
4314                 // one more normal
4315                 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4316
4317                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4318                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4319                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4320                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4321                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4322         }
4323         else
4324         {
4325                 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4326                 VectorScale(left,  1.0f, r_refdef.view.frustum[1].normal);
4327                 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4328                 VectorScale(up,  1.0f, r_refdef.view.frustum[3].normal);
4329                 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4330                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4331                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4332                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4333                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4334                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4335         }
4336         r_refdef.view.numfrustumplanes = 5;
4337
4338         if (r_refdef.view.useclipplane)
4339         {
4340                 r_refdef.view.numfrustumplanes = 6;
4341                 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4342         }
4343
4344         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4345                 PlaneClassify(r_refdef.view.frustum + i);
4346
4347         // LadyHavoc: note to all quake engine coders, Quake had a special case
4348         // for 90 degrees which assumed a square view (wrong), so I removed it,
4349         // Quake2 has it disabled as well.
4350
4351         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4352         //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4353         //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4354         //PlaneClassify(&frustum[0]);
4355
4356         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4357         //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4358         //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4359         //PlaneClassify(&frustum[1]);
4360
4361         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4362         //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4363         //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4364         //PlaneClassify(&frustum[2]);
4365
4366         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4367         //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4368         //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4369         //PlaneClassify(&frustum[3]);
4370
4371         // nearclip plane
4372         //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4373         //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4374         //PlaneClassify(&frustum[4]);
4375 }
4376
4377 static void R_View_UpdateWithScissor(const int *myscissor)
4378 {
4379         R_Main_ResizeViewCache();
4380         R_View_SetFrustum(myscissor);
4381         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4382         R_View_UpdateEntityVisible();
4383 }
4384
4385 static void R_View_Update(void)
4386 {
4387         R_Main_ResizeViewCache();
4388         R_View_SetFrustum(NULL);
4389         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4390         R_View_UpdateEntityVisible();
4391 }
4392
4393 float viewscalefpsadjusted = 1.0f;
4394
4395 static void R_GetScaledViewSize(int width, int height, int *outwidth, int *outheight)
4396 {
4397         float scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
4398         scale = bound(0.03125f, scale, 1.0f);
4399         *outwidth = (int)ceil(width * scale);
4400         *outheight = (int)ceil(height * scale);
4401 }
4402
4403 void R_SetupView(qboolean allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4404 {
4405         const float *customclipplane = NULL;
4406         float plane[4];
4407         int /*rtwidth,*/ rtheight;
4408         if (r_refdef.view.useclipplane && allowwaterclippingplane)
4409         {
4410                 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4411                 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4412                 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4413                 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4414                         dist = r_refdef.view.clipplane.dist;
4415                 plane[0] = r_refdef.view.clipplane.normal[0];
4416                 plane[1] = r_refdef.view.clipplane.normal[1];
4417                 plane[2] = r_refdef.view.clipplane.normal[2];
4418                 plane[3] = -dist;
4419                 customclipplane = plane;
4420         }
4421
4422         //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
4423         rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
4424
4425         if (!r_refdef.view.useperspective)
4426                 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);
4427         else if (vid.stencil && r_useinfinitefarclip.integer)
4428                 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);
4429         else
4430                 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);
4431         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4432         R_SetViewport(&r_refdef.view.viewport);
4433 }
4434
4435 void R_EntityMatrix(const matrix4x4_t *matrix)
4436 {
4437         if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4438         {
4439                 gl_modelmatrixchanged = false;
4440                 gl_modelmatrix = *matrix;
4441                 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4442                 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4443                 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4444                 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4445                 CHECKGLERROR
4446                 switch(vid.renderpath)
4447                 {
4448                 case RENDERPATH_GL32:
4449                 case RENDERPATH_GLES2:
4450                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4451                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4452                         break;
4453                 }
4454         }
4455 }
4456
4457 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4458 {
4459         r_viewport_t viewport;
4460
4461         CHECKGLERROR
4462
4463         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
4464         R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4465         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4466         R_SetViewport(&viewport);
4467         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4468         GL_Color(1, 1, 1, 1);
4469         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4470         GL_BlendFunc(GL_ONE, GL_ZERO);
4471         GL_ScissorTest(false);
4472         GL_DepthMask(false);
4473         GL_DepthRange(0, 1);
4474         GL_DepthTest(false);
4475         GL_DepthFunc(GL_LEQUAL);
4476         R_EntityMatrix(&identitymatrix);
4477         R_Mesh_ResetTextureState();
4478         GL_PolygonOffset(0, 0);
4479         switch(vid.renderpath)
4480         {
4481         case RENDERPATH_GL32:
4482         case RENDERPATH_GLES2:
4483                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4484                 break;
4485         }
4486         GL_CullFace(GL_NONE);
4487
4488         CHECKGLERROR
4489 }
4490
4491 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4492 {
4493         R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4494 }
4495
4496 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4497 {
4498         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4499         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4500         GL_Color(1, 1, 1, 1);
4501         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4502         GL_BlendFunc(GL_ONE, GL_ZERO);
4503         GL_ScissorTest(true);
4504         GL_DepthMask(true);
4505         GL_DepthRange(0, 1);
4506         GL_DepthTest(true);
4507         GL_DepthFunc(GL_LEQUAL);
4508         R_EntityMatrix(&identitymatrix);
4509         R_Mesh_ResetTextureState();
4510         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4511         switch(vid.renderpath)
4512         {
4513         case RENDERPATH_GL32:
4514         case RENDERPATH_GLES2:
4515                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4516                 break;
4517         }
4518         GL_CullFace(r_refdef.view.cullface_back);
4519 }
4520
4521 /*
4522 ================
4523 R_RenderView_UpdateViewVectors
4524 ================
4525 */
4526 void R_RenderView_UpdateViewVectors(void)
4527 {
4528         // break apart the view matrix into vectors for various purposes
4529         // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4530         // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4531         Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4532         VectorNegate(r_refdef.view.left, r_refdef.view.right);
4533         // make an inverted copy of the view matrix for tracking sprites
4534         Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4535 }
4536
4537 void R_RenderTarget_FreeUnused(qboolean force)
4538 {
4539         unsigned int i, j, end;
4540         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4541         for (i = 0; i < end; i++)
4542         {
4543                 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4544                 // free resources for rendertargets that have not been used for a while
4545                 // (note: this check is run after the frame render, so any targets used
4546                 // this frame will not be affected even at low framerates)
4547                 if (r && (realtime - r->lastusetime > 0.2 || force))
4548                 {
4549                         if (r->fbo)
4550                                 R_Mesh_DestroyFramebufferObject(r->fbo);
4551                         for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4552                                 if (r->colortexture[j])
4553                                         R_FreeTexture(r->colortexture[j]);
4554                         if (r->depthtexture)
4555                                 R_FreeTexture(r->depthtexture);
4556                         Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4557                 }
4558         }
4559 }
4560
4561 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4562 {
4563         float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4564         x1 = x * iw;
4565         x2 = (x + w) * iw;
4566         y1 = (th - y) * ih;
4567         y2 = (th - y - h) * ih;
4568         texcoord2f[0] = x1;
4569         texcoord2f[2] = x2;
4570         texcoord2f[4] = x2;
4571         texcoord2f[6] = x1;
4572         texcoord2f[1] = y1;
4573         texcoord2f[3] = y1;
4574         texcoord2f[5] = y2;
4575         texcoord2f[7] = y2;
4576 }
4577
4578 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)
4579 {
4580         unsigned int i, j, end;
4581         r_rendertarget_t *r = NULL;
4582         char vabuf[256];
4583         // first try to reuse an existing slot if possible
4584         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4585         for (i = 0; i < end; i++)
4586         {
4587                 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4588                 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)
4589                         break;
4590         }
4591         if (i == end)
4592         {
4593                 // no unused exact match found, so we have to make one in the first unused slot
4594                 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4595                 r->texturewidth = texturewidth;
4596                 r->textureheight = textureheight;
4597                 r->colortextype[0] = colortextype0;
4598                 r->colortextype[1] = colortextype1;
4599                 r->colortextype[2] = colortextype2;
4600                 r->colortextype[3] = colortextype3;
4601                 r->depthtextype = depthtextype;
4602                 r->depthisrenderbuffer = depthisrenderbuffer;
4603                 for (j = 0; j < 4; j++)
4604                         if (r->colortextype[j])
4605                                 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);
4606                 if (r->depthtextype)
4607                 {
4608                         if (r->depthisrenderbuffer)
4609                                 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);
4610                         else
4611                                 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);
4612                 }
4613                 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4614         }
4615         r_refdef.stats[r_stat_rendertargets_used]++;
4616         r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4617         r->lastusetime = realtime;
4618         R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4619         return r;
4620 }
4621
4622 static void R_Water_StartFrame(void)
4623 {
4624         int waterwidth, waterheight;
4625
4626         if (vid.width > (int)vid.maxtexturesize_2d || vid.height > (int)vid.maxtexturesize_2d)
4627                 return;
4628
4629         // set waterwidth and waterheight to the water resolution that will be
4630         // used (often less than the screen resolution for faster rendering)
4631         waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width);
4632         waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height);
4633         R_GetScaledViewSize(waterwidth, waterheight, &waterwidth, &waterheight);
4634
4635         if (!r_water.integer || r_showsurfaces.integer)
4636                 waterwidth = waterheight = 0;
4637
4638         // set up variables that will be used in shader setup
4639         r_fb.water.waterwidth = waterwidth;
4640         r_fb.water.waterheight = waterheight;
4641         r_fb.water.texturewidth = waterwidth;
4642         r_fb.water.textureheight = waterheight;
4643         r_fb.water.camerawidth = waterwidth;
4644         r_fb.water.cameraheight = waterheight;
4645         r_fb.water.screenscale[0] = 0.5f;
4646         r_fb.water.screenscale[1] = 0.5f;
4647         r_fb.water.screencenter[0] = 0.5f;
4648         r_fb.water.screencenter[1] = 0.5f;
4649         r_fb.water.enabled = waterwidth != 0;
4650
4651         r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4652         r_fb.water.numwaterplanes = 0;
4653 }
4654
4655 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4656 {
4657         int planeindex, bestplaneindex, vertexindex;
4658         vec3_t mins, maxs, normal, center, v, n;
4659         vec_t planescore, bestplanescore;
4660         mplane_t plane;
4661         r_waterstate_waterplane_t *p;
4662         texture_t *t = R_GetCurrentTexture(surface->texture);
4663
4664         rsurface.texture = t;
4665         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4666         // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4667         if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4668                 return;
4669         // average the vertex normals, find the surface bounds (after deformvertexes)
4670         Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4671         Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4672         VectorCopy(n, normal);
4673         VectorCopy(v, mins);
4674         VectorCopy(v, maxs);
4675         for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4676         {
4677                 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4678                 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4679                 VectorAdd(normal, n, normal);
4680                 mins[0] = min(mins[0], v[0]);
4681                 mins[1] = min(mins[1], v[1]);
4682                 mins[2] = min(mins[2], v[2]);
4683                 maxs[0] = max(maxs[0], v[0]);
4684                 maxs[1] = max(maxs[1], v[1]);
4685                 maxs[2] = max(maxs[2], v[2]);
4686         }
4687         VectorNormalize(normal);
4688         VectorMAM(0.5f, mins, 0.5f, maxs, center);
4689
4690         VectorCopy(normal, plane.normal);
4691         VectorNormalize(plane.normal);
4692         plane.dist = DotProduct(center, plane.normal);
4693         PlaneClassify(&plane);
4694         if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4695         {
4696                 // skip backfaces (except if nocullface is set)
4697 //              if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4698 //                      return;
4699                 VectorNegate(plane.normal, plane.normal);
4700                 plane.dist *= -1;
4701                 PlaneClassify(&plane);
4702         }
4703
4704
4705         // find a matching plane if there is one
4706         bestplaneindex = -1;
4707         bestplanescore = 1048576.0f;
4708         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4709         {
4710                 if(p->camera_entity == t->camera_entity)
4711                 {
4712                         planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4713                         if (bestplaneindex < 0 || bestplanescore > planescore)
4714                         {
4715                                 bestplaneindex = planeindex;
4716                                 bestplanescore = planescore;
4717                         }
4718                 }
4719         }
4720         planeindex = bestplaneindex;
4721
4722         // if this surface does not fit any known plane rendered this frame, add one
4723         if (planeindex < 0 || bestplanescore > 0.001f)
4724         {
4725                 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4726                 {
4727                         // store the new plane
4728                         planeindex = r_fb.water.numwaterplanes++;
4729                         p = r_fb.water.waterplanes + planeindex;
4730                         p->plane = plane;
4731                         // clear materialflags and pvs
4732                         p->materialflags = 0;
4733                         p->pvsvalid = false;
4734                         p->camera_entity = t->camera_entity;
4735                         VectorCopy(mins, p->mins);
4736                         VectorCopy(maxs, p->maxs);
4737                 }
4738                 else
4739                 {
4740                         // We're totally screwed.
4741                         return;
4742                 }
4743         }
4744         else
4745         {
4746                 // merge mins/maxs when we're adding this surface to the plane
4747                 p = r_fb.water.waterplanes + planeindex;
4748                 p->mins[0] = min(p->mins[0], mins[0]);
4749                 p->mins[1] = min(p->mins[1], mins[1]);
4750                 p->mins[2] = min(p->mins[2], mins[2]);
4751                 p->maxs[0] = max(p->maxs[0], maxs[0]);
4752                 p->maxs[1] = max(p->maxs[1], maxs[1]);
4753                 p->maxs[2] = max(p->maxs[2], maxs[2]);
4754         }
4755         // merge this surface's materialflags into the waterplane
4756         p->materialflags |= t->currentmaterialflags;
4757         if(!(p->materialflags & MATERIALFLAG_CAMERA))
4758         {
4759                 // merge this surface's PVS into the waterplane
4760                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4761                  && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4762                 {
4763                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4764                         p->pvsvalid = true;
4765                 }
4766         }
4767 }
4768
4769 extern cvar_t r_drawparticles;
4770 extern cvar_t r_drawdecals;
4771
4772 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4773 {
4774         int myscissor[4];
4775         r_refdef_view_t originalview;
4776         r_refdef_view_t myview;
4777         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;
4778         r_waterstate_waterplane_t *p;
4779         vec3_t visorigin;
4780         r_rendertarget_t *rt;
4781
4782         originalview = r_refdef.view;
4783
4784         // lowquality hack, temporarily shut down some cvars and restore afterwards
4785         qualityreduction = r_water_lowquality.integer;
4786         if (qualityreduction > 0)
4787         {
4788                 if (qualityreduction >= 1)
4789                 {
4790                         old_r_shadows = r_shadows.integer;
4791                         old_r_worldrtlight = r_shadow_realtime_world.integer;
4792                         old_r_dlight = r_shadow_realtime_dlight.integer;
4793                         Cvar_SetValueQuick(&r_shadows, 0);
4794                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4795                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4796                 }
4797                 if (qualityreduction >= 2)
4798                 {
4799                         old_r_dynamic = r_dynamic.integer;
4800                         old_r_particles = r_drawparticles.integer;
4801                         old_r_decals = r_drawdecals.integer;
4802                         Cvar_SetValueQuick(&r_dynamic, 0);
4803                         Cvar_SetValueQuick(&r_drawparticles, 0);
4804                         Cvar_SetValueQuick(&r_drawdecals, 0);
4805                 }
4806         }
4807
4808         for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4809         {
4810                 p->rt_reflection = NULL;
4811                 p->rt_refraction = NULL;
4812                 p->rt_camera = NULL;
4813         }
4814
4815         // render views
4816         r_refdef.view = originalview;
4817         r_refdef.view.showdebug = false;
4818         r_refdef.view.width = r_fb.water.waterwidth;
4819         r_refdef.view.height = r_fb.water.waterheight;
4820         r_refdef.view.useclipplane = true;
4821         myview = r_refdef.view;
4822         r_fb.water.renderingscene = true;
4823         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4824         {
4825                 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4826                         continue;
4827
4828                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4829                 {
4830                         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);
4831                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4832                                 goto error;
4833                         r_refdef.view = myview;
4834                         Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4835                         Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4836                         if(r_water_scissormode.integer)
4837                         {
4838                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4839                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4840                                 {
4841                                         p->rt_reflection = NULL;
4842                                         p->rt_refraction = NULL;
4843                                         p->rt_camera = NULL;
4844                                         continue;
4845                                 }
4846                         }
4847
4848                         r_refdef.view.clipplane = p->plane;
4849                         // reflected view origin may be in solid, so don't cull with it
4850                         r_refdef.view.usevieworiginculling = false;
4851                         // reverse the cullface settings for this render
4852                         r_refdef.view.cullface_front = GL_FRONT;
4853                         r_refdef.view.cullface_back = GL_BACK;
4854                         // combined pvs (based on what can be seen from each surface center)
4855                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4856                         {
4857                                 r_refdef.view.usecustompvs = true;
4858                                 if (p->pvsvalid)
4859                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4860                                 else
4861                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4862                         }
4863
4864                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4865                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4866                         GL_ScissorTest(false);
4867                         R_ClearScreen(r_refdef.fogenabled);
4868                         GL_ScissorTest(true);
4869                         if(r_water_scissormode.integer & 2)
4870                                 R_View_UpdateWithScissor(myscissor);
4871                         else
4872                                 R_View_Update();
4873                         R_AnimCache_CacheVisibleEntities();
4874                         if(r_water_scissormode.integer & 1)
4875                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4876                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4877
4878                         r_fb.water.hideplayer = false;
4879                         p->rt_reflection = rt;
4880                 }
4881
4882                 // render the normal view scene and copy into texture
4883                 // (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)
4884                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
4885                 {
4886                         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);
4887                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4888                                 goto error;
4889                         r_refdef.view = myview;
4890                         if(r_water_scissormode.integer)
4891                         {
4892                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4893                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4894                                 {
4895                                         p->rt_reflection = NULL;
4896                                         p->rt_refraction = NULL;
4897                                         p->rt_camera = NULL;
4898                                         continue;
4899                                 }
4900                         }
4901
4902                         // combined pvs (based on what can be seen from each surface center)
4903                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4904                         {
4905                                 r_refdef.view.usecustompvs = true;
4906                                 if (p->pvsvalid)
4907                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4908                                 else
4909                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4910                         }
4911
4912                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
4913
4914                         r_refdef.view.clipplane = p->plane;
4915                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
4916                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
4917
4918                         if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
4919                         {
4920                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
4921                                 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
4922                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
4923                                 R_RenderView_UpdateViewVectors();
4924                                 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
4925                                 {
4926                                         r_refdef.view.usecustompvs = true;
4927                                         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);
4928                                 }
4929                         }
4930
4931                         PlaneClassify(&r_refdef.view.clipplane);
4932
4933                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4934                         GL_ScissorTest(false);
4935                         R_ClearScreen(r_refdef.fogenabled);
4936                         GL_ScissorTest(true);
4937                         if(r_water_scissormode.integer & 2)
4938                                 R_View_UpdateWithScissor(myscissor);
4939                         else
4940                                 R_View_Update();
4941                         R_AnimCache_CacheVisibleEntities();
4942                         if(r_water_scissormode.integer & 1)
4943                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4944                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4945
4946                         r_fb.water.hideplayer = false;
4947                         p->rt_refraction = rt;
4948                 }
4949                 else if (p->materialflags & MATERIALFLAG_CAMERA)
4950                 {
4951                         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);
4952                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4953                                 goto error;
4954                         r_refdef.view = myview;
4955
4956                         r_refdef.view.clipplane = p->plane;
4957                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
4958                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
4959
4960                         r_refdef.view.width = r_fb.water.camerawidth;
4961                         r_refdef.view.height = r_fb.water.cameraheight;
4962                         r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
4963                         r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
4964                         r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
4965                         r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
4966
4967                         if(p->camera_entity)
4968                         {
4969                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
4970                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
4971                         }
4972
4973                         // note: all of the view is used for displaying... so
4974                         // there is no use in scissoring
4975
4976                         // reverse the cullface settings for this render
4977                         r_refdef.view.cullface_front = GL_FRONT;
4978                         r_refdef.view.cullface_back = GL_BACK;
4979                         // also reverse the view matrix
4980                         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
4981                         R_RenderView_UpdateViewVectors();
4982                         if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
4983                         {
4984                                 r_refdef.view.usecustompvs = true;
4985                                 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);
4986                         }
4987                         
4988                         // camera needs no clipplane
4989                         r_refdef.view.useclipplane = false;
4990                         // TODO: is the camera origin always valid?  if so we don't need to clear this
4991                         r_refdef.view.usevieworiginculling = false;
4992
4993                         PlaneClassify(&r_refdef.view.clipplane);
4994
4995                         r_fb.water.hideplayer = false;
4996
4997                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4998                         GL_ScissorTest(false);
4999                         R_ClearScreen(r_refdef.fogenabled);
5000                         GL_ScissorTest(true);
5001                         R_View_Update();
5002                         R_AnimCache_CacheVisibleEntities();
5003                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5004
5005                         r_fb.water.hideplayer = false;
5006                         p->rt_camera = rt;
5007                 }
5008
5009         }
5010         r_fb.water.renderingscene = false;
5011         r_refdef.view = originalview;
5012         R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5013         R_View_Update();
5014         R_AnimCache_CacheVisibleEntities();
5015         goto finish;
5016 error:
5017         r_refdef.view = originalview;
5018         r_fb.water.renderingscene = false;
5019         Cvar_SetValueQuick(&r_water, 0);
5020         Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed!  Turned off r_water.\n");
5021 finish:
5022         // lowquality hack, restore cvars
5023         if (qualityreduction > 0)
5024         {
5025                 if (qualityreduction >= 1)
5026                 {
5027                         Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5028                         Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5029                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5030                 }
5031                 if (qualityreduction >= 2)
5032                 {
5033                         Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5034                         Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5035                         Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5036                 }
5037         }
5038 }
5039
5040 static void R_Bloom_StartFrame(void)
5041 {
5042         int screentexturewidth, screentextureheight;
5043         int viewwidth, viewheight;
5044         textype_t textype = TEXTYPE_COLORBUFFER;
5045
5046         // clear the pointers to rendertargets from last frame as they're stale
5047         r_fb.rt_screen = NULL;
5048         r_fb.rt_bloom = NULL;
5049
5050         switch (vid.renderpath)
5051         {
5052         case RENDERPATH_GL32:
5053                 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5054                 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5055                 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5056                 break;
5057         case RENDERPATH_GLES2:
5058                 r_fb.usedepthtextures = false;
5059                 break;
5060         }
5061
5062         if (r_viewscale_fpsscaling.integer)
5063         {
5064                 double actualframetime;
5065                 double targetframetime;
5066                 double adjust;
5067                 actualframetime = r_refdef.lastdrawscreentime;
5068                 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5069                 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5070                 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5071                 if (r_viewscale_fpsscaling_stepsize.value > 0)
5072                         adjust = (int)(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5073                 viewscalefpsadjusted += adjust;
5074                 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5075         }
5076         else
5077                 viewscalefpsadjusted = 1.0f;
5078
5079         R_GetScaledViewSize(r_refdef.view.width, r_refdef.view.height, &viewwidth, &viewheight);
5080
5081         // set bloomwidth and bloomheight to the bloom resolution that will be
5082         // used (often less than the screen resolution for faster rendering)
5083         r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, vid.width);
5084         r_fb.bloomheight = r_fb.bloomwidth * vid.height / vid.width;
5085         r_fb.bloomheight = bound(1, r_fb.bloomheight, vid.height);
5086         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5087         r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5088
5089         // calculate desired texture sizes
5090         screentexturewidth = viewwidth;
5091         screentextureheight = viewheight;
5092
5093         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))
5094         {
5095                 Cvar_SetValueQuick(&r_bloom, 0);
5096                 Cvar_SetValueQuick(&r_motionblur, 0);
5097                 Cvar_SetValueQuick(&r_damageblur, 0);
5098         }
5099
5100         // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5101         if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5102         {
5103                 if (r_fb.ghosttexture)
5104                         R_FreeTexture(r_fb.ghosttexture);
5105                 r_fb.ghosttexture = NULL;
5106
5107                 r_fb.screentexturewidth = screentexturewidth;
5108                 r_fb.screentextureheight = screentextureheight;
5109                 r_fb.textype = textype;
5110
5111                 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5112                 {
5113                         if (r_motionblur.value > 0 || r_damageblur.value > 0)
5114                                 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);
5115                         r_fb.ghosttexture_valid = false;
5116                 }
5117         }
5118
5119         if (r_bloom.integer)
5120         {
5121                 // bloom texture is a different resolution
5122                 r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.width);
5123                 r_fb.bloomheight = r_fb.bloomwidth * r_refdef.view.height / r_refdef.view.width;
5124                 r_fb.bloomheight = bound(1, r_fb.bloomheight, r_refdef.view.height);
5125         }
5126         else
5127                 r_fb.bloomwidth = r_fb.bloomheight = 0;
5128
5129         r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5130
5131         r_refdef.view.clear = true;
5132 }
5133
5134 static void R_Bloom_MakeTexture(void)
5135 {
5136         int x, range, dir;
5137         float xoffset, yoffset, r, brighten;
5138         float colorscale = r_bloom_colorscale.value;
5139         r_viewport_t bloomviewport;
5140         r_rendertarget_t *prev, *cur;
5141         textype_t textype = r_fb.rt_screen->colortextype[0];
5142
5143         r_refdef.stats[r_stat_bloom]++;
5144
5145         R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5146
5147         // scale down screen texture to the bloom texture size
5148         CHECKGLERROR
5149         prev = r_fb.rt_screen;
5150         cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5151         R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5152         R_SetViewport(&bloomviewport);
5153         GL_CullFace(GL_NONE);
5154         GL_DepthTest(false);
5155         GL_BlendFunc(GL_ONE, GL_ZERO);
5156         GL_Color(colorscale, colorscale, colorscale, 1);
5157         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5158         // TODO: do boxfilter scale-down in shader?
5159         R_SetupShader_Generic(prev->colortexture[0], false, true, true);
5160         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5161         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5162         // we now have a properly scaled bloom image
5163
5164         // multiply bloom image by itself as many times as desired to darken it
5165         // TODO: if people actually use this it could be done more quickly in the previous shader pass
5166         for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5167         {
5168                 prev = cur;
5169                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5170                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5171                 x *= 2;
5172                 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5173                 if(x <= 2)
5174                         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0);
5175                 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5176                 GL_Color(1,1,1,1); // no fix factor supported here
5177                 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5178                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5179                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5180                 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5181         }
5182         CHECKGLERROR
5183
5184         range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5185         brighten = r_bloom_brighten.value;
5186         brighten = sqrt(brighten);
5187         if(range >= 1)
5188                 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5189
5190         for (dir = 0;dir < 2;dir++)
5191         {
5192                 prev = cur;
5193                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5194                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5195                 // blend on at multiple vertical offsets to achieve a vertical blur
5196                 // TODO: do offset blends using GLSL
5197                 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5198                 CHECKGLERROR
5199                 GL_BlendFunc(GL_ONE, GL_ZERO);
5200                 CHECKGLERROR
5201                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5202                 CHECKGLERROR
5203                 for (x = -range;x <= range;x++)
5204                 {
5205                         if (!dir){xoffset = 0;yoffset = x;}
5206                         else {xoffset = x;yoffset = 0;}
5207                         xoffset /= (float)prev->texturewidth;
5208                         yoffset /= (float)prev->textureheight;
5209                         // compute a texcoord array with the specified x and y offset
5210                         r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5211                         r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5212                         r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5213                         r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5214                         r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5215                         r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5216                         r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5217                         r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5218                         // this r value looks like a 'dot' particle, fading sharply to
5219                         // black at the edges
5220                         // (probably not realistic but looks good enough)
5221                         //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5222                         //r = brighten/(range*2+1);
5223                         r = brighten / (range * 2 + 1);
5224                         if(range >= 1)
5225                                 r *= (1 - x*x/(float)((range+1)*(range+1)));
5226                         if (r <= 0)
5227                                 continue;
5228                         CHECKGLERROR
5229                         GL_Color(r, r, r, 1);
5230                         CHECKGLERROR
5231                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5232                         CHECKGLERROR
5233                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5234                         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5235                         CHECKGLERROR
5236                         GL_BlendFunc(GL_ONE, GL_ONE);
5237                         CHECKGLERROR
5238                 }
5239         }
5240
5241         // now we have the bloom image, so keep track of it
5242         r_fb.rt_bloom = cur;
5243 }
5244
5245 static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5246 {
5247         dpuint64 permutation;
5248         float uservecs[4][4];
5249         rtexture_t *viewtexture;
5250         rtexture_t *bloomtexture;
5251
5252         R_EntityMatrix(&identitymatrix);
5253
5254         if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
5255         {
5256                 // declare variables
5257                 float blur_factor, blur_mouseaccel, blur_velocity;
5258                 static float blur_average; 
5259                 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5260
5261                 // set a goal for the factoring
5262                 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value) 
5263                         / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5264                 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value) 
5265                         / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5266                 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value) 
5267                         + (blur_mouseaccel * r_motionblur_mousefactor.value));
5268
5269                 // from the goal, pick an averaged value between goal and last value
5270                 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5271                 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5272
5273                 // enforce minimum amount of blur 
5274                 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5275
5276                 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5277
5278                 // calculate values into a standard alpha
5279                 cl.motionbluralpha = 1 - exp(-
5280                                 (
5281                                         (r_motionblur.value * blur_factor / 80)
5282                                         +
5283                                         (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5284                                 )
5285                                 /
5286                                 max(0.0001, cl.time - cl.oldtime) // fps independent
5287                                 );
5288
5289                 // randomization for the blur value to combat persistent ghosting
5290                 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5291                 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5292
5293                 // apply the blur
5294                 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5295                 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5296                 {
5297                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5298                         GL_Color(1, 1, 1, cl.motionbluralpha);
5299                         R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5300                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5301                         R_SetupShader_Generic(r_fb.ghosttexture, false, true, true);
5302                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5303                         r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5304                 }
5305
5306                 // updates old view angles for next pass
5307                 VectorCopy(cl.viewangles, blur_oldangles);
5308
5309                 // copy view into the ghost texture
5310                 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5311                 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5312                 r_fb.ghosttexture_valid = true;
5313         }
5314
5315         if (r_fb.bloomwidth)
5316         {
5317                 // make the bloom texture
5318                 R_Bloom_MakeTexture();
5319         }
5320
5321 #if _MSC_VER >= 1400
5322 #define sscanf sscanf_s
5323 #endif
5324         memset(uservecs, 0, sizeof(uservecs));
5325         if (r_glsl_postprocess_uservec1_enable.integer)
5326                 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5327         if (r_glsl_postprocess_uservec2_enable.integer)
5328                 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5329         if (r_glsl_postprocess_uservec3_enable.integer)
5330                 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5331         if (r_glsl_postprocess_uservec4_enable.integer)
5332                 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5333
5334         // render to the screen fbo
5335         R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5336         GL_Color(1, 1, 1, 1);
5337         GL_BlendFunc(GL_ONE, GL_ZERO);
5338
5339         viewtexture = r_fb.rt_screen->colortexture[0];
5340         bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5341
5342         if (r_rendertarget_debug.integer >= 0)
5343         {
5344                 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5345                 if (rt && rt->colortexture[0])
5346                 {
5347                         viewtexture = rt->colortexture[0];
5348                         bloomtexture = NULL;
5349                 }
5350         }
5351
5352         R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5353         switch(vid.renderpath)
5354         {
5355         case RENDERPATH_GL32:
5356         case RENDERPATH_GLES2:
5357                 permutation =
5358                         (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5359                         | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5360                         | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5361                         | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5362                         | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5363                 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5364                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First     , viewtexture);
5365                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second    , bloomtexture);
5366                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps       );
5367                 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]);
5368                 if (r_glsl_permutation->loc_PixelSize               >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize         , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5369                 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]);
5370                 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]);
5371                 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]);
5372                 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]);
5373                 if (r_glsl_permutation->loc_Saturation              >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation        , r_glsl_saturation.value);
5374                 if (r_glsl_permutation->loc_PixelToScreenTexCoord   >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
5375                 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);
5376                 if (r_glsl_permutation->loc_ColorFringe             >= 0) qglUniform1f(r_glsl_permutation->loc_ColorFringe, r_colorfringe.value );
5377                 break;
5378         }
5379         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5380         r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5381 }
5382
5383 matrix4x4_t r_waterscrollmatrix;
5384
5385 void R_UpdateFog(void)
5386 {
5387         // Nehahra fog
5388         if (gamemode == GAME_NEHAHRA)
5389         {
5390                 if (gl_fogenable.integer)
5391                 {
5392                         r_refdef.oldgl_fogenable = true;
5393                         r_refdef.fog_density = gl_fogdensity.value;
5394                         r_refdef.fog_red = gl_fogred.value;
5395                         r_refdef.fog_green = gl_foggreen.value;
5396                         r_refdef.fog_blue = gl_fogblue.value;
5397                         r_refdef.fog_alpha = 1;
5398                         r_refdef.fog_start = 0;
5399                         r_refdef.fog_end = gl_skyclip.value;
5400                         r_refdef.fog_height = 1<<30;
5401                         r_refdef.fog_fadedepth = 128;
5402                 }
5403                 else if (r_refdef.oldgl_fogenable)
5404                 {
5405                         r_refdef.oldgl_fogenable = false;
5406                         r_refdef.fog_density = 0;
5407                         r_refdef.fog_red = 0;
5408                         r_refdef.fog_green = 0;
5409                         r_refdef.fog_blue = 0;
5410                         r_refdef.fog_alpha = 0;
5411                         r_refdef.fog_start = 0;
5412                         r_refdef.fog_end = 0;
5413                         r_refdef.fog_height = 1<<30;
5414                         r_refdef.fog_fadedepth = 128;
5415                 }
5416         }
5417
5418         // fog parms
5419         r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5420         r_refdef.fog_start = max(0, r_refdef.fog_start);
5421         r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5422
5423         if (r_refdef.fog_density && r_drawfog.integer)
5424         {
5425                 r_refdef.fogenabled = true;
5426                 // this is the point where the fog reaches 0.9986 alpha, which we
5427                 // consider a good enough cutoff point for the texture
5428                 // (0.9986 * 256 == 255.6)
5429                 if (r_fog_exp2.integer)
5430                         r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5431                 else
5432                         r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5433                 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5434                 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5435                 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5436                 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5437                         R_BuildFogHeightTexture();
5438                 // fog color was already set
5439                 // update the fog texture
5440                 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)
5441                         R_BuildFogTexture();
5442                 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5443                 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5444         }
5445         else
5446                 r_refdef.fogenabled = false;
5447
5448         // fog color
5449         if (r_refdef.fog_density)
5450         {
5451                 r_refdef.fogcolor[0] = r_refdef.fog_red;
5452                 r_refdef.fogcolor[1] = r_refdef.fog_green;
5453                 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5454
5455                 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5456                 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5457                 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5458                 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5459
5460                 {
5461                         vec3_t fogvec;
5462                         VectorCopy(r_refdef.fogcolor, fogvec);
5463                         //   color.rgb *= ContrastBoost * SceneBrightness;
5464                         VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5465                         r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5466                         r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5467                         r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5468                 }
5469         }
5470 }
5471
5472 void R_UpdateVariables(void)
5473 {
5474         R_Textures_Frame();
5475
5476         r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5477
5478         r_refdef.farclip = r_farclip_base.value;
5479         if (r_refdef.scene.worldmodel)
5480                 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5481         r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5482
5483         if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5484                 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5485         r_refdef.polygonfactor = 0;
5486         r_refdef.polygonoffset = 0;
5487
5488         r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5489         r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5490         r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5491         r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5492         r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5493         if (r_refdef.scene.worldmodel)
5494         {
5495                 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5496         }
5497         if (r_showsurfaces.integer)
5498         {
5499                 r_refdef.scene.rtworld = false;
5500                 r_refdef.scene.rtworldshadows = false;
5501                 r_refdef.scene.rtdlight = false;
5502                 r_refdef.scene.rtdlightshadows = false;
5503                 r_refdef.scene.lightmapintensity = 0;
5504         }
5505
5506         r_gpuskeletal = false;
5507         switch(vid.renderpath)
5508         {
5509         case RENDERPATH_GL32:
5510                 r_gpuskeletal = r_glsl_skeletal.integer && !r_showsurfaces.integer;
5511         case RENDERPATH_GLES2:
5512                 if(!vid_gammatables_trivial)
5513                 {
5514                         if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5515                         {
5516                                 // build GLSL gamma texture
5517 #define RAMPWIDTH 256
5518                                 unsigned short ramp[RAMPWIDTH * 3];
5519                                 unsigned char rampbgr[RAMPWIDTH][4];
5520                                 int i;
5521
5522                                 r_texture_gammaramps_serial = vid_gammatables_serial;
5523
5524                                 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5525                                 for(i = 0; i < RAMPWIDTH; ++i)
5526                                 {
5527                                         rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5528                                         rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5529                                         rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5530                                         rampbgr[i][3] = 0;
5531                                 }
5532                                 if (r_texture_gammaramps)
5533                                 {
5534                                         R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1);
5535                                 }
5536                                 else
5537                                 {
5538                                         r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5539                                 }
5540                         }
5541                 }
5542                 else
5543                 {
5544                         // remove GLSL gamma texture
5545                 }
5546                 break;
5547         }
5548 }
5549
5550 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5551 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5552 /*
5553 ================
5554 R_SelectScene
5555 ================
5556 */
5557 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5558         if( scenetype != r_currentscenetype ) {
5559                 // store the old scenetype
5560                 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5561                 r_currentscenetype = scenetype;
5562                 // move in the new scene
5563                 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5564         }
5565 }
5566
5567 /*
5568 ================
5569 R_GetScenePointer
5570 ================
5571 */
5572 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5573 {
5574         // of course, we could also add a qboolean that provides a lock state and a ReleaseScenePointer function..
5575         if( scenetype == r_currentscenetype ) {
5576                 return &r_refdef.scene;
5577         } else {
5578                 return &r_scenes_store[ scenetype ];
5579         }
5580 }
5581
5582 static int R_SortEntities_Compare(const void *ap, const void *bp)
5583 {
5584         const entity_render_t *a = *(const entity_render_t **)ap;
5585         const entity_render_t *b = *(const entity_render_t **)bp;
5586
5587         // 1. compare model
5588         if(a->model < b->model)
5589                 return -1;
5590         if(a->model > b->model)
5591                 return +1;
5592
5593         // 2. compare skin
5594         // TODO possibly calculate the REAL skinnum here first using
5595         // skinscenes?
5596         if(a->skinnum < b->skinnum)
5597                 return -1;
5598         if(a->skinnum > b->skinnum)
5599                 return +1;
5600
5601         // everything we compared is equal
5602         return 0;
5603 }
5604 static void R_SortEntities(void)
5605 {
5606         // below or equal 2 ents, sorting never gains anything
5607         if(r_refdef.scene.numentities <= 2)
5608                 return;
5609         // sort
5610         qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5611 }
5612
5613 /*
5614 ================
5615 R_RenderView
5616 ================
5617 */
5618 extern cvar_t r_shadow_bouncegrid;
5619 extern cvar_t v_isometric;
5620 extern void V_MakeViewIsometric(void);
5621 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5622 {
5623         matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5624         int viewfbo = 0;
5625         rtexture_t *viewdepthtexture = NULL;
5626         rtexture_t *viewcolortexture = NULL;
5627         int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5628
5629         // finish any 2D rendering that was queued
5630         DrawQ_Finish();
5631
5632         if (r_timereport_active)
5633                 R_TimeReport("start");
5634         r_textureframe++; // used only by R_GetCurrentTexture
5635         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5636
5637         if(R_CompileShader_CheckStaticParms())
5638                 R_GLSL_Restart_f(&cmd_client);
5639
5640         if (!r_drawentities.integer)
5641                 r_refdef.scene.numentities = 0;
5642         else if (r_sortentities.integer)
5643                 R_SortEntities();
5644
5645         R_AnimCache_ClearCache();
5646
5647         /* adjust for stereo display */
5648         if(R_Stereo_Active())
5649         {
5650                 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);
5651                 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5652         }
5653
5654         if (r_refdef.view.isoverlay)
5655         {
5656                 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5657                 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5658                 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5659                 R_TimeReport("depthclear");
5660
5661                 r_refdef.view.showdebug = false;
5662
5663                 r_fb.water.enabled = false;
5664                 r_fb.water.numwaterplanes = 0;
5665
5666                 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5667
5668                 r_refdef.view.matrix = originalmatrix;
5669
5670                 CHECKGLERROR
5671                 return;
5672         }
5673
5674         if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5675         {
5676                 r_refdef.view.matrix = originalmatrix;
5677                 return;
5678         }
5679
5680         r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5681         if (v_isometric.integer && r_refdef.view.ismain)
5682                 V_MakeViewIsometric();
5683
5684         r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5685
5686         if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5687                 // in sRGB fallback, behave similar to true sRGB: convert this
5688                 // value from linear to sRGB
5689                 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5690
5691         R_RenderView_UpdateViewVectors();
5692
5693         R_Shadow_UpdateWorldLightSelection();
5694
5695         // this will set up r_fb.rt_screen
5696         R_Bloom_StartFrame();
5697
5698         // apply bloom brightness offset
5699         if(r_fb.rt_bloom)
5700                 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5701
5702         // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5703         if (r_fb.rt_screen)
5704         {
5705                 viewfbo = r_fb.rt_screen->fbo;
5706                 viewdepthtexture = r_fb.rt_screen->depthtexture;
5707                 viewcolortexture = r_fb.rt_screen->colortexture[0];
5708                 viewx = 0;
5709                 viewy = 0;
5710                 viewwidth = width;
5711                 viewheight = height;
5712         }
5713
5714         R_Water_StartFrame();
5715
5716         CHECKGLERROR
5717         if (r_timereport_active)
5718                 R_TimeReport("viewsetup");
5719
5720         R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5721
5722         // clear the whole fbo every frame - otherwise the driver will consider
5723         // it to be an inter-frame texture and stall in multi-gpu configurations
5724         if (r_fb.rt_screen)
5725                 GL_ScissorTest(false);
5726         R_ClearScreen(r_refdef.fogenabled);
5727         if (r_timereport_active)
5728                 R_TimeReport("viewclear");
5729
5730         r_refdef.view.clear = true;
5731
5732         r_refdef.view.showdebug = true;
5733
5734         R_View_Update();
5735         if (r_timereport_active)
5736                 R_TimeReport("visibility");
5737
5738         R_AnimCache_CacheVisibleEntities();
5739         if (r_timereport_active)
5740                 R_TimeReport("animcache");
5741
5742         R_Shadow_UpdateBounceGridTexture();
5743         // R_Shadow_UpdateBounceGridTexture called R_TimeReport a few times internally, so we don't need to do that here.
5744
5745         r_fb.water.numwaterplanes = 0;
5746         if (r_fb.water.enabled)
5747                 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5748
5749         // for the actual view render we use scissoring a fair amount, so scissor
5750         // test needs to be on
5751         if (r_fb.rt_screen)
5752                 GL_ScissorTest(true);
5753         GL_Scissor(viewx, viewy, viewwidth, viewheight);
5754         R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5755         r_fb.water.numwaterplanes = 0;
5756
5757         // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5758         GL_ScissorTest(false);
5759
5760         R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
5761         if (r_timereport_active)
5762                 R_TimeReport("blendview");
5763
5764         r_refdef.view.matrix = originalmatrix;
5765
5766         CHECKGLERROR
5767
5768         // go back to 2d rendering
5769         DrawQ_Start();
5770 }
5771
5772 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5773 {
5774         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5775         {
5776                 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5777                 if (r_timereport_active)
5778                         R_TimeReport("waterworld");
5779         }
5780
5781         // don't let sound skip if going slow
5782         if (r_refdef.scene.extraupdate)
5783                 S_ExtraUpdate ();
5784
5785         R_DrawModelsAddWaterPlanes();
5786         if (r_timereport_active)
5787                 R_TimeReport("watermodels");
5788
5789         if (r_fb.water.numwaterplanes)
5790         {
5791                 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5792                 if (r_timereport_active)
5793                         R_TimeReport("waterscenes");
5794         }
5795 }
5796
5797 extern cvar_t cl_locs_show;
5798 static void R_DrawLocs(void);
5799 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5800 static void R_DrawModelDecals(void);
5801 extern qboolean r_shadow_usingdeferredprepass;
5802 extern int r_shadow_shadowmapatlas_modelshadows_size;
5803 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5804 {
5805         qboolean shadowmapping = false;
5806
5807         if (r_timereport_active)
5808                 R_TimeReport("beginscene");
5809
5810         r_refdef.stats[r_stat_renders]++;
5811
5812         R_UpdateFog();
5813
5814         // don't let sound skip if going slow
5815         if (r_refdef.scene.extraupdate)
5816                 S_ExtraUpdate ();
5817
5818         R_MeshQueue_BeginScene();
5819
5820         R_SkyStartFrame();
5821
5822         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);
5823
5824         if (r_timereport_active)
5825                 R_TimeReport("skystartframe");
5826
5827         if (cl.csqc_vidvars.drawworld)
5828         {
5829                 // don't let sound skip if going slow
5830                 if (r_refdef.scene.extraupdate)
5831                         S_ExtraUpdate ();
5832
5833                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5834                 {
5835                         r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5836                         if (r_timereport_active)
5837                                 R_TimeReport("worldsky");
5838                 }
5839
5840                 if (R_DrawBrushModelsSky() && r_timereport_active)
5841                         R_TimeReport("bmodelsky");
5842
5843                 if (skyrendermasked && skyrenderlater)
5844                 {
5845                         // we have to force off the water clipping plane while rendering sky
5846                         R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5847                         R_Sky();
5848                         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5849                         if (r_timereport_active)
5850                                 R_TimeReport("sky");
5851                 }
5852         }
5853
5854         // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5855         r_shadow_viewfbo = viewfbo;
5856         r_shadow_viewdepthtexture = viewdepthtexture;
5857         r_shadow_viewcolortexture = viewcolortexture;
5858         r_shadow_viewx = viewx;
5859         r_shadow_viewy = viewy;
5860         r_shadow_viewwidth = viewwidth;
5861         r_shadow_viewheight = viewheight;
5862
5863         R_Shadow_PrepareModelShadows();
5864         R_Shadow_PrepareLights();
5865         if (r_timereport_active)
5866                 R_TimeReport("preparelights");
5867
5868         // render all the shadowmaps that will be used for this view
5869         shadowmapping = R_Shadow_ShadowMappingEnabled();
5870         if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
5871         {
5872                 R_Shadow_DrawShadowMaps();
5873                 if (r_timereport_active)
5874                         R_TimeReport("shadowmaps");
5875         }
5876
5877         // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
5878         if (r_shadow_usingdeferredprepass)
5879                 R_Shadow_DrawPrepass();
5880
5881         // now we begin the forward pass of the view render
5882         if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
5883         {
5884                 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
5885                 if (r_timereport_active)
5886                         R_TimeReport("worlddepth");
5887         }
5888         if (r_depthfirst.integer >= 2)
5889         {
5890                 R_DrawModelsDepth();
5891                 if (r_timereport_active)
5892                         R_TimeReport("modeldepth");
5893         }
5894
5895         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
5896         {
5897                 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
5898                 if (r_timereport_active)
5899                         R_TimeReport("world");
5900         }
5901
5902         // don't let sound skip if going slow
5903         if (r_refdef.scene.extraupdate)
5904                 S_ExtraUpdate ();
5905
5906         R_DrawModels();
5907         if (r_timereport_active)
5908                 R_TimeReport("models");
5909
5910         // don't let sound skip if going slow
5911         if (r_refdef.scene.extraupdate)
5912                 S_ExtraUpdate ();
5913
5914         if (!r_shadow_usingdeferredprepass)
5915         {
5916                 R_Shadow_DrawLights();
5917                 if (r_timereport_active)
5918                         R_TimeReport("rtlights");
5919         }
5920
5921         // don't let sound skip if going slow
5922         if (r_refdef.scene.extraupdate)
5923                 S_ExtraUpdate ();
5924
5925         if (cl.csqc_vidvars.drawworld)
5926         {
5927                 R_DrawModelDecals();
5928                 if (r_timereport_active)
5929                         R_TimeReport("modeldecals");
5930
5931                 R_DrawParticles();
5932                 if (r_timereport_active)
5933                         R_TimeReport("particles");
5934
5935                 R_DrawExplosions();
5936                 if (r_timereport_active)
5937                         R_TimeReport("explosions");
5938         }
5939
5940         if (r_refdef.view.showdebug)
5941         {
5942                 if (cl_locs_show.integer)
5943                 {
5944                         R_DrawLocs();
5945                         if (r_timereport_active)
5946                                 R_TimeReport("showlocs");
5947                 }
5948
5949                 if (r_drawportals.integer)
5950                 {
5951                         R_DrawPortals();
5952                         if (r_timereport_active)
5953                                 R_TimeReport("portals");
5954                 }
5955
5956                 if (r_showbboxes_client.value > 0)
5957                 {
5958                         R_DrawEntityBBoxes(CLVM_prog);
5959                         if (r_timereport_active)
5960                                 R_TimeReport("clbboxes");
5961                 }
5962                 if (r_showbboxes.value > 0)
5963                 {
5964                         R_DrawEntityBBoxes(SVVM_prog);
5965                         if (r_timereport_active)
5966                                 R_TimeReport("svbboxes");
5967                 }
5968         }
5969
5970         if (r_transparent.integer)
5971         {
5972                 R_MeshQueue_RenderTransparent();
5973                 if (r_timereport_active)
5974                         R_TimeReport("drawtrans");
5975         }
5976
5977         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))
5978         {
5979                 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
5980                 if (r_timereport_active)
5981                         R_TimeReport("worlddebug");
5982                 R_DrawModelsDebug();
5983                 if (r_timereport_active)
5984                         R_TimeReport("modeldebug");
5985         }
5986
5987         if (cl.csqc_vidvars.drawworld)
5988         {
5989                 R_Shadow_DrawCoronas();
5990                 if (r_timereport_active)
5991                         R_TimeReport("coronas");
5992         }
5993
5994         // don't let sound skip if going slow
5995         if (r_refdef.scene.extraupdate)
5996                 S_ExtraUpdate ();
5997 }
5998
5999 static const unsigned short bboxelements[36] =
6000 {
6001         5, 1, 3, 5, 3, 7,
6002         6, 2, 0, 6, 0, 4,
6003         7, 3, 2, 7, 2, 6,
6004         4, 0, 1, 4, 1, 5,
6005         4, 5, 7, 4, 7, 6,
6006         1, 0, 2, 1, 2, 3,
6007 };
6008
6009 #define BBOXEDGES 13
6010 static const float bboxedges[BBOXEDGES][6] = 
6011 {
6012         // whole box
6013         { 0, 0, 0, 1, 1, 1 },
6014         // bottom edges
6015         { 0, 0, 0, 0, 1, 0 },
6016         { 0, 0, 0, 1, 0, 0 },
6017         { 0, 1, 0, 1, 1, 0 },
6018         { 1, 0, 0, 1, 1, 0 },
6019         // top edges
6020         { 0, 0, 1, 0, 1, 1 },
6021         { 0, 0, 1, 1, 0, 1 },
6022         { 0, 1, 1, 1, 1, 1 },
6023         { 1, 0, 1, 1, 1, 1 },
6024         // vertical edges
6025         { 0, 0, 0, 0, 0, 1 },
6026         { 1, 0, 0, 1, 0, 1 },
6027         { 0, 1, 0, 0, 1, 1 },
6028         { 1, 1, 0, 1, 1, 1 },
6029 };
6030
6031 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6032 {
6033         int numvertices = BBOXEDGES * 8;
6034         float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6035         int numtriangles = BBOXEDGES * 12;
6036         unsigned short elements[BBOXEDGES * 36];
6037         int i, edge;
6038         float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6039
6040         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6041
6042         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6043         GL_DepthMask(false);
6044         GL_DepthRange(0, 1);
6045         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6046
6047         for (edge = 0; edge < BBOXEDGES; edge++)
6048         {
6049                 for (i = 0; i < 3; i++)
6050                 {
6051                         edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6052                         edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6053                 }
6054                 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6055                 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6056                 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6057                 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6058                 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6059                 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6060                 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6061                 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6062                 for (i = 0; i < 36; i++)
6063                         elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6064         }
6065         R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6066         if (r_refdef.fogenabled)
6067         {
6068                 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6069                 {
6070                         f1 = RSurf_FogVertex(v);
6071                         f2 = 1 - f1;
6072                         c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6073                         c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6074                         c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6075                 }
6076         }
6077         R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6078         R_Mesh_ResetTextureState();
6079         R_SetupShader_Generic_NoTexture(false, false);
6080         R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6081 }
6082
6083 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6084 {
6085         // hacky overloading of the parameters
6086         prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6087         int i;
6088         float color[4];
6089         prvm_edict_t *edict;
6090
6091         GL_CullFace(GL_NONE);
6092         R_SetupShader_Generic_NoTexture(false, false);
6093
6094         for (i = 0;i < numsurfaces;i++)
6095         {
6096                 edict = PRVM_EDICT_NUM(surfacelist[i]);
6097                 switch ((int)PRVM_serveredictfloat(edict, solid))
6098                 {
6099                         case SOLID_NOT:      Vector4Set(color, 1, 1, 1, 0.05);break;
6100                         case SOLID_TRIGGER:  Vector4Set(color, 1, 0, 1, 0.10);break;
6101                         case SOLID_BBOX:     Vector4Set(color, 0, 1, 0, 0.10);break;
6102                         case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6103                         case SOLID_BSP:      Vector4Set(color, 0, 0, 1, 0.05);break;
6104                         case SOLID_CORPSE:   Vector4Set(color, 1, 0.5, 0, 0.05);break;
6105                         default:             Vector4Set(color, 0, 0, 0, 0.50);break;
6106                 }
6107                 if (prog == CLVM_prog)
6108                         color[3] *= r_showbboxes_client.value;
6109                 else
6110                         color[3] *= r_showbboxes.value;
6111                 color[3] = bound(0, color[3], 1);
6112                 GL_DepthTest(!r_showdisabledepthtest.integer);
6113                 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6114         }
6115 }
6116
6117 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6118 {
6119         int i;
6120         prvm_edict_t *edict;
6121         vec3_t center;
6122
6123         if (prog == NULL)
6124                 return;
6125
6126         for (i = 0; i < prog->num_edicts; i++)
6127         {
6128                 edict = PRVM_EDICT_NUM(i);
6129                 if (edict->priv.server->free)
6130                         continue;
6131                 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6132                 if (PRVM_gameedictedict(edict, tag_entity) != 0)
6133                         continue;
6134                 if (prog == SVVM_prog && PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6135                         continue;
6136                 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6137                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6138         }
6139 }
6140
6141 static const int nomodelelement3i[24] =
6142 {
6143         5, 2, 0,
6144         5, 1, 2,
6145         5, 0, 3,
6146         5, 3, 1,
6147         0, 2, 4,
6148         2, 1, 4,
6149         3, 0, 4,
6150         1, 3, 4
6151 };
6152
6153 static const unsigned short nomodelelement3s[24] =
6154 {
6155         5, 2, 0,
6156         5, 1, 2,
6157         5, 0, 3,
6158         5, 3, 1,
6159         0, 2, 4,
6160         2, 1, 4,
6161         3, 0, 4,
6162         1, 3, 4
6163 };
6164
6165 static const float nomodelvertex3f[6*3] =
6166 {
6167         -16,   0,   0,
6168          16,   0,   0,
6169           0, -16,   0,
6170           0,  16,   0,
6171           0,   0, -16,
6172           0,   0,  16
6173 };
6174
6175 static const float nomodelcolor4f[6*4] =
6176 {
6177         0.0f, 0.0f, 0.5f, 1.0f,
6178         0.0f, 0.0f, 0.5f, 1.0f,
6179         0.0f, 0.5f, 0.0f, 1.0f,
6180         0.0f, 0.5f, 0.0f, 1.0f,
6181         0.5f, 0.0f, 0.0f, 1.0f,
6182         0.5f, 0.0f, 0.0f, 1.0f
6183 };
6184
6185 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6186 {
6187         int i;
6188         float f1, f2, *c;
6189         float color4f[6*4];
6190
6191         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);
6192
6193         // this is only called once per entity so numsurfaces is always 1, and
6194         // surfacelist is always {0}, so this code does not handle batches
6195
6196         if (rsurface.ent_flags & RENDER_ADDITIVE)
6197         {
6198                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6199                 GL_DepthMask(false);
6200         }
6201         else if (ent->alpha < 1)
6202         {
6203                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6204                 GL_DepthMask(false);
6205         }
6206         else
6207         {
6208                 GL_BlendFunc(GL_ONE, GL_ZERO);
6209                 GL_DepthMask(true);
6210         }
6211         GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6212         GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6213         GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6214         GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6215         memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6216         for (i = 0, c = color4f;i < 6;i++, c += 4)
6217         {
6218                 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6219                 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6220                 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6221                 c[3] *= ent->alpha;
6222         }
6223         if (r_refdef.fogenabled)
6224         {
6225                 for (i = 0, c = color4f;i < 6;i++, c += 4)
6226                 {
6227                         f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6228                         f2 = 1 - f1;
6229                         c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6230                         c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6231                         c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6232                 }
6233         }
6234 //      R_Mesh_ResetTextureState();
6235         R_SetupShader_Generic_NoTexture(false, false);
6236         R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6237         R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6238 }
6239
6240 void R_DrawNoModel(entity_render_t *ent)
6241 {
6242         vec3_t org;
6243         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6244         if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6245                 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6246         else
6247                 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6248 }
6249
6250 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6251 {
6252         vec3_t right1, right2, diff, normal;
6253
6254         VectorSubtract (org2, org1, normal);
6255
6256         // calculate 'right' vector for start
6257         VectorSubtract (r_refdef.view.origin, org1, diff);
6258         CrossProduct (normal, diff, right1);
6259         VectorNormalize (right1);
6260
6261         // calculate 'right' vector for end
6262         VectorSubtract (r_refdef.view.origin, org2, diff);
6263         CrossProduct (normal, diff, right2);
6264         VectorNormalize (right2);
6265
6266         vert[ 0] = org1[0] + width * right1[0];
6267         vert[ 1] = org1[1] + width * right1[1];
6268         vert[ 2] = org1[2] + width * right1[2];
6269         vert[ 3] = org1[0] - width * right1[0];
6270         vert[ 4] = org1[1] - width * right1[1];
6271         vert[ 5] = org1[2] - width * right1[2];
6272         vert[ 6] = org2[0] - width * right2[0];
6273         vert[ 7] = org2[1] - width * right2[1];
6274         vert[ 8] = org2[2] - width * right2[2];
6275         vert[ 9] = org2[0] + width * right2[0];
6276         vert[10] = org2[1] + width * right2[1];
6277         vert[11] = org2[2] + width * right2[2];
6278 }
6279
6280 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)
6281 {
6282         vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6283         vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6284         vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6285         vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6286         vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6287         vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6288         vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6289         vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6290         vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6291         vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6292         vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6293         vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6294 }
6295
6296 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6297 {
6298         int i;
6299         float *vertex3f;
6300         float v[3];
6301         VectorSet(v, x, y, z);
6302         for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6303                 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6304                         break;
6305         if (i == mesh->numvertices)
6306         {
6307                 if (mesh->numvertices < mesh->maxvertices)
6308                 {
6309                         VectorCopy(v, vertex3f);
6310                         mesh->numvertices++;
6311                 }
6312                 return mesh->numvertices;
6313         }
6314         else
6315                 return i;
6316 }
6317
6318 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6319 {
6320         int i;
6321         int *e, element[3];
6322         element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6323         element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6324         e = mesh->element3i + mesh->numtriangles * 3;
6325         for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6326         {
6327                 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6328                 if (mesh->numtriangles < mesh->maxtriangles)
6329                 {
6330                         *e++ = element[0];
6331                         *e++ = element[1];
6332                         *e++ = element[2];
6333                         mesh->numtriangles++;
6334                 }
6335                 element[1] = element[2];
6336         }
6337 }
6338
6339 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6340 {
6341         int i;
6342         int *e, element[3];
6343         element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6344         element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6345         e = mesh->element3i + mesh->numtriangles * 3;
6346         for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6347         {
6348                 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6349                 if (mesh->numtriangles < mesh->maxtriangles)
6350                 {
6351                         *e++ = element[0];
6352                         *e++ = element[1];
6353                         *e++ = element[2];
6354                         mesh->numtriangles++;
6355                 }
6356                 element[1] = element[2];
6357         }
6358 }
6359
6360 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6361 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6362 {
6363         int planenum, planenum2;
6364         int w;
6365         int tempnumpoints;
6366         mplane_t *plane, *plane2;
6367         double maxdist;
6368         double temppoints[2][256*3];
6369         // figure out how large a bounding box we need to properly compute this brush
6370         maxdist = 0;
6371         for (w = 0;w < numplanes;w++)
6372                 maxdist = max(maxdist, fabs(planes[w].dist));
6373         // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6374         maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6375         for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6376         {
6377                 w = 0;
6378                 tempnumpoints = 4;
6379                 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6380                 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6381                 {
6382                         if (planenum2 == planenum)
6383                                 continue;
6384                         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);
6385                         w = !w;
6386                 }
6387                 if (tempnumpoints < 3)
6388                         continue;
6389                 // generate elements forming a triangle fan for this polygon
6390                 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6391         }
6392 }
6393
6394 static qboolean R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6395 {
6396         if(parms[0] == 0 && parms[1] == 0)
6397                 return false;
6398         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6399                 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6400                         return false;
6401         return true;
6402 }
6403
6404 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6405 {
6406         double index, f;
6407         index = parms[2] + rsurface.shadertime * parms[3];
6408         index -= floor(index);
6409         switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6410         {
6411         default:
6412         case Q3WAVEFUNC_NONE:
6413         case Q3WAVEFUNC_NOISE:
6414         case Q3WAVEFUNC_COUNT:
6415                 f = 0;
6416                 break;
6417         case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6418         case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6419         case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6420         case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6421         case Q3WAVEFUNC_TRIANGLE:
6422                 index *= 4;
6423                 f = index - floor(index);
6424                 if (index < 1)
6425                 {
6426                         // f = f;
6427                 }
6428                 else if (index < 2)
6429                         f = 1 - f;
6430                 else if (index < 3)
6431                         f = -f;
6432                 else
6433                         f = -(1 - f);
6434                 break;
6435         }
6436         f = parms[0] + parms[1] * f;
6437         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6438                 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6439         return (float) f;
6440 }
6441
6442 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6443 {
6444         int w, h, idx;
6445         float shadertime;
6446         float f;
6447         float offsetd[2];
6448         float tcmat[12];
6449         matrix4x4_t matrix, temp;
6450         // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6451         // it's better to have one huge fixup every 9 hours than gradual
6452         // degradation over time which looks consistently bad after many hours.
6453         //
6454         // tcmod scroll in particular suffers from this degradation which can't be
6455         // effectively worked around even with floor() tricks because we don't
6456         // know if tcmod scroll is the last tcmod being applied, and for clampmap
6457         // a workaround involving floor() would be incorrect anyway...
6458         shadertime = rsurface.shadertime;
6459         if (shadertime >= 32768.0f)
6460                 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6461         switch(tcmod->tcmod)
6462         {
6463                 case Q3TCMOD_COUNT:
6464                 case Q3TCMOD_NONE:
6465                         if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6466                                 matrix = r_waterscrollmatrix;
6467                         else
6468                                 matrix = identitymatrix;
6469                         break;
6470                 case Q3TCMOD_ENTITYTRANSLATE:
6471                         // this is used in Q3 to allow the gamecode to control texcoord
6472                         // scrolling on the entity, which is not supported in darkplaces yet.
6473                         Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6474                         break;
6475                 case Q3TCMOD_ROTATE:
6476                         Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6477                         Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6478                         Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6479                         break;
6480                 case Q3TCMOD_SCALE:
6481                         Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6482                         break;
6483                 case Q3TCMOD_SCROLL:
6484                         // this particular tcmod is a "bug for bug" compatible one with regards to
6485                         // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6486                         // specifically did the wrapping and so we must mimic that...
6487                         offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6488                         offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6489                         Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6490                         break;
6491                 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6492                         w = (int) tcmod->parms[0];
6493                         h = (int) tcmod->parms[1];
6494                         f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6495                         f = f - floor(f);
6496                         idx = (int) floor(f * w * h);
6497                         Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6498                         break;
6499                 case Q3TCMOD_STRETCH:
6500                         f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6501                         Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6502                         break;
6503                 case Q3TCMOD_TRANSFORM:
6504                         VectorSet(tcmat +  0, tcmod->parms[0], tcmod->parms[1], 0);
6505                         VectorSet(tcmat +  3, tcmod->parms[2], tcmod->parms[3], 0);
6506                         VectorSet(tcmat +  6, 0                   , 0                , 1);
6507                         VectorSet(tcmat +  9, tcmod->parms[4], tcmod->parms[5], 0);
6508                         Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6509                         break;
6510                 case Q3TCMOD_TURBULENT:
6511                         // this is handled in the RSurf_PrepareVertices function
6512                         matrix = identitymatrix;
6513                         break;
6514         }
6515         temp = *texmatrix;
6516         Matrix4x4_Concat(texmatrix, &matrix, &temp);
6517 }
6518
6519 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6520 {
6521         int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6522         char name[MAX_QPATH];
6523         skinframe_t *skinframe;
6524         unsigned char pixels[296*194];
6525         strlcpy(cache->name, skinname, sizeof(cache->name));
6526         dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6527         if (developer_loading.integer)
6528                 Con_Printf("loading %s\n", name);
6529         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6530         if (!skinframe || !skinframe->base)
6531         {
6532                 unsigned char *f;
6533                 fs_offset_t filesize;
6534                 skinframe = NULL;
6535                 f = FS_LoadFile(name, tempmempool, true, &filesize);
6536                 if (f)
6537                 {
6538                         if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6539                                 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6540                         Mem_Free(f);
6541                 }
6542         }
6543         cache->skinframe = skinframe;
6544 }
6545
6546 texture_t *R_GetCurrentTexture(texture_t *t)
6547 {
6548         int i, q;
6549         const entity_render_t *ent = rsurface.entity;
6550         dp_model_t *model = ent->model; // when calling this, ent must not be NULL
6551         q3shaderinfo_layer_tcmod_t *tcmod;
6552         float specularscale = 0.0f;
6553
6554         if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6555                 return t->currentframe;
6556         t->update_lastrenderframe = r_textureframe;
6557         t->update_lastrenderentity = (void *)ent;
6558
6559         if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6560                 t->camera_entity = ent->entitynumber;
6561         else
6562                 t->camera_entity = 0;
6563
6564         // switch to an alternate material if this is a q1bsp animated material
6565         {
6566                 texture_t *texture = t;
6567                 int s = rsurface.ent_skinnum;
6568                 if ((unsigned int)s >= (unsigned int)model->numskins)
6569                         s = 0;
6570                 if (model->skinscenes)
6571                 {
6572                         if (model->skinscenes[s].framecount > 1)
6573                                 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6574                         else
6575                                 s = model->skinscenes[s].firstframe;
6576                 }
6577                 if (s > 0)
6578                         t = t + s * model->num_surfaces;
6579                 if (t->animated)
6580                 {
6581                         // use an alternate animation if the entity's frame is not 0,
6582                         // and only if the texture has an alternate animation
6583                         if (t->animated == 2) // q2bsp
6584                                 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6585                         else if (rsurface.ent_alttextures && t->anim_total[1])
6586                                 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6587                         else
6588                                 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6589                 }
6590                 texture->currentframe = t;
6591         }
6592
6593         // update currentskinframe to be a qw skin or animation frame
6594         if (rsurface.ent_qwskin >= 0)
6595         {
6596                 i = rsurface.ent_qwskin;
6597                 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6598                 {
6599                         r_qwskincache_size = cl.maxclients;
6600                         if (r_qwskincache)
6601                                 Mem_Free(r_qwskincache);
6602                         r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6603                 }
6604                 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6605                         R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6606                 t->currentskinframe = r_qwskincache[i].skinframe;
6607                 if (t->materialshaderpass && t->currentskinframe == NULL)
6608                         t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6609         }
6610         else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6611                 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6612         if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6613                 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6614
6615         t->currentmaterialflags = t->basematerialflags;
6616         t->currentalpha = rsurface.entity->alpha * t->basealpha;
6617         if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_water.integer || r_novis.integer || r_trippy.integer))
6618                 t->currentalpha *= r_wateralpha.value;
6619         if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6620                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6621         if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6622                 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6623
6624         // decide on which type of lighting to use for this surface
6625         if (rsurface.entity->render_modellight_forced)
6626                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6627         if (rsurface.entity->render_rtlight_disabled)
6628                 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6629         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6630         {
6631                 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6632                 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NORTLIGHT;
6633                 for (q = 0; q < 3; q++)
6634                 {
6635                         t->render_glowmod[q] = rsurface.entity->glowmod[q];
6636                         t->render_modellight_lightdir[q] = q == 2;
6637                         t->render_modellight_ambient[q] = 1;
6638                         t->render_modellight_diffuse[q] = 0;
6639                         t->render_modellight_specular[q] = 0;
6640                         t->render_lightmap_ambient[q] = 0;
6641                         t->render_lightmap_diffuse[q] = 0;
6642                         t->render_lightmap_specular[q] = 0;
6643                         t->render_rtlight_diffuse[q] = 0;
6644                         t->render_rtlight_specular[q] = 0;
6645                 }
6646         }
6647         else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6648         {
6649                 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6650                 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT;
6651                 for (q = 0; q < 3; q++)
6652                 {
6653                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6654                         t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6655                         t->render_modellight_lightdir[q] = q == 2;
6656                         t->render_modellight_diffuse[q] = 0;
6657                         t->render_modellight_specular[q] = 0;
6658                         t->render_lightmap_ambient[q] = 0;
6659                         t->render_lightmap_diffuse[q] = 0;
6660                         t->render_lightmap_specular[q] = 0;
6661                         t->render_rtlight_diffuse[q] = 0;
6662                         t->render_rtlight_specular[q] = 0;
6663                 }
6664         }
6665         else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6666         {
6667                 // ambient + single direction light (modellight)
6668                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6669                 for (q = 0; q < 3; q++)
6670                 {
6671                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6672                         t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6673                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6674                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6675                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6676                         t->render_lightmap_ambient[q] = 0;
6677                         t->render_lightmap_diffuse[q] = 0;
6678                         t->render_lightmap_specular[q] = 0;
6679                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6680                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6681                 }
6682         }
6683         else
6684         {
6685                 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6686                 for (q = 0; q < 3; q++)
6687                 {
6688                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6689                         t->render_modellight_lightdir[q] = q == 2;
6690                         t->render_modellight_ambient[q] = 0;
6691                         t->render_modellight_diffuse[q] = 0;
6692                         t->render_modellight_specular[q] = 0;
6693                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6694                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6695                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6696                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6697                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6698                 }
6699         }
6700
6701         if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6702         {
6703                 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6704                 // attribute, we punt it to the lightmap path and hope for the best,
6705                 // but lighting doesn't work.
6706                 //
6707                 // FIXME: this is fine for effects but CSQC polygons should be subject
6708                 // to lighting.
6709                 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6710                 for (q = 0; q < 3; q++)
6711                 {
6712                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6713                         t->render_modellight_lightdir[q] = q == 2;
6714                         t->render_modellight_ambient[q] = 0;
6715                         t->render_modellight_diffuse[q] = 0;
6716                         t->render_modellight_specular[q] = 0;
6717                         t->render_lightmap_ambient[q] = 0;
6718                         t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6719                         t->render_lightmap_specular[q] = 0;
6720                         t->render_rtlight_diffuse[q] = 0;
6721                         t->render_rtlight_specular[q] = 0;
6722                 }
6723         }
6724
6725         for (q = 0; q < 3; q++)
6726         {
6727                 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6728                 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6729         }
6730
6731         if (rsurface.ent_flags & RENDER_ADDITIVE)
6732                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6733         else if (t->currentalpha < 1)
6734                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6735         // LadyHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6736         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6737                 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6738         if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6739                 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6740         if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6741                 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6742         if (t->backgroundshaderpass)
6743                 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6744         if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6745         {
6746                 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6747                         t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6748         }
6749         else
6750                 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6751         if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6752         {
6753                 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6754                 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6755         }
6756         if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6757                 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6758
6759         // there is no tcmod
6760         if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6761         {
6762                 t->currenttexmatrix = r_waterscrollmatrix;
6763                 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6764         }
6765         else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6766         {
6767                 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6768                 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6769         }
6770
6771         if (t->materialshaderpass)
6772                 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6773                         R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6774
6775         t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6776         if (t->currentskinframe->qpixels)
6777                 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6778         t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6779         if (!t->basetexture)
6780                 t->basetexture = r_texture_notexture;
6781         t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6782         t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6783         t->nmaptexture = t->currentskinframe->nmap;
6784         if (!t->nmaptexture)
6785                 t->nmaptexture = r_texture_blanknormalmap;
6786         t->glosstexture = r_texture_black;
6787         t->glowtexture = t->currentskinframe->glow;
6788         t->fogtexture = t->currentskinframe->fog;
6789         t->reflectmasktexture = t->currentskinframe->reflect;
6790         if (t->backgroundshaderpass)
6791         {
6792                 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6793                         R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6794                 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6795                 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6796                 t->backgroundglosstexture = r_texture_black;
6797                 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6798                 if (!t->backgroundnmaptexture)
6799                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6800                 // make sure that if glow is going to be used, both textures are not NULL
6801                 if (!t->backgroundglowtexture && t->glowtexture)
6802                         t->backgroundglowtexture = r_texture_black;
6803                 if (!t->glowtexture && t->backgroundglowtexture)
6804                         t->glowtexture = r_texture_black;
6805         }
6806         else
6807         {
6808                 t->backgroundbasetexture = r_texture_white;
6809                 t->backgroundnmaptexture = r_texture_blanknormalmap;
6810                 t->backgroundglosstexture = r_texture_black;
6811                 t->backgroundglowtexture = NULL;
6812         }
6813         t->specularpower = r_shadow_glossexponent.value;
6814         // TODO: store reference values for these in the texture?
6815         if (r_shadow_gloss.integer > 0)
6816         {
6817                 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
6818                 {
6819                         if (r_shadow_glossintensity.value > 0)
6820                         {
6821                                 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
6822                                 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
6823                                 specularscale = r_shadow_glossintensity.value;
6824                         }
6825                 }
6826                 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
6827                 {
6828                         t->glosstexture = r_texture_white;
6829                         t->backgroundglosstexture = r_texture_white;
6830                         specularscale = r_shadow_gloss2intensity.value;
6831                         t->specularpower = r_shadow_gloss2exponent.value;
6832                 }
6833         }
6834         specularscale *= t->specularscalemod;
6835         t->specularpower *= t->specularpowermod;
6836
6837         // lightmaps mode looks bad with dlights using actual texturing, so turn
6838         // off the colormap and glossmap, but leave the normalmap on as it still
6839         // accurately represents the shading involved
6840         if (gl_lightmaps.integer)
6841         {
6842                 t->basetexture = r_texture_grey128;
6843                 t->pantstexture = r_texture_black;
6844                 t->shirttexture = r_texture_black;
6845                 if (gl_lightmaps.integer < 2)
6846                         t->nmaptexture = r_texture_blanknormalmap;
6847                 t->glosstexture = r_texture_black;
6848                 t->glowtexture = NULL;
6849                 t->fogtexture = NULL;
6850                 t->reflectmasktexture = NULL;
6851                 t->backgroundbasetexture = NULL;
6852                 if (gl_lightmaps.integer < 2)
6853                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6854                 t->backgroundglosstexture = r_texture_black;
6855                 t->backgroundglowtexture = NULL;
6856                 specularscale = 0;
6857                 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
6858         }
6859
6860         if (specularscale != 1.0f)
6861         {
6862                 for (q = 0; q < 3; q++)
6863                 {
6864                         t->render_modellight_specular[q] *= specularscale;
6865                         t->render_lightmap_specular[q] *= specularscale;
6866                         t->render_rtlight_specular[q] *= specularscale;
6867                 }
6868         }
6869
6870         t->currentblendfunc[0] = GL_ONE;
6871         t->currentblendfunc[1] = GL_ZERO;
6872         if (t->currentmaterialflags & MATERIALFLAG_ADD)
6873         {
6874                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6875                 t->currentblendfunc[1] = GL_ONE;
6876         }
6877         else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
6878         {
6879                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6880                 t->currentblendfunc[1] = GL_ONE_MINUS_SRC_ALPHA;
6881         }
6882         else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6883         {
6884                 t->currentblendfunc[0] = t->customblendfunc[0];
6885                 t->currentblendfunc[1] = t->customblendfunc[1];
6886         }
6887
6888         return t;
6889 }
6890
6891 rsurfacestate_t rsurface;
6892
6893 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
6894 {
6895         dp_model_t *model = ent->model;
6896         //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
6897         //      return;
6898         rsurface.entity = (entity_render_t *)ent;
6899         rsurface.skeleton = ent->skeleton;
6900         memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
6901         rsurface.ent_skinnum = ent->skinnum;
6902         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;
6903         rsurface.ent_flags = ent->flags;
6904         if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
6905                 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
6906         rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
6907         rsurface.matrix = ent->matrix;
6908         rsurface.inversematrix = ent->inversematrix;
6909         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
6910         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
6911         R_EntityMatrix(&rsurface.matrix);
6912         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
6913         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
6914         rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
6915         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
6916         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
6917         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
6918         memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
6919         rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
6920         rsurface.basepolygonfactor = r_refdef.polygonfactor;
6921         rsurface.basepolygonoffset = r_refdef.polygonoffset;
6922         if (ent->model->brush.submodel && !prepass)
6923         {
6924                 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
6925                 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
6926         }
6927         // if the animcache code decided it should use the shader path, skip the deform step
6928         rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
6929         rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
6930         rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
6931         rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
6932         rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
6933         if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
6934         {
6935                 if (ent->animcache_vertex3f)
6936                 {
6937                         r_refdef.stats[r_stat_batch_entitycache_count]++;
6938                         r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
6939                         r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
6940                         r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
6941                         rsurface.modelvertex3f = ent->animcache_vertex3f;
6942                         rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
6943                         rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
6944                         rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
6945                         rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
6946                         rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
6947                         rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
6948                         rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
6949                         rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
6950                         rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
6951                         rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
6952                         rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
6953                 }
6954                 else if (wanttangents)
6955                 {
6956                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
6957                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
6958                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
6959                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
6960                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6961                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6962                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6963                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6964                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
6965                         rsurface.modelvertex3f_vertexbuffer = NULL;
6966                         rsurface.modelvertex3f_bufferoffset = 0;
6967                         rsurface.modelvertex3f_vertexbuffer = 0;
6968                         rsurface.modelvertex3f_bufferoffset = 0;
6969                         rsurface.modelsvector3f_vertexbuffer = 0;
6970                         rsurface.modelsvector3f_bufferoffset = 0;
6971                         rsurface.modeltvector3f_vertexbuffer = 0;
6972                         rsurface.modeltvector3f_bufferoffset = 0;
6973                         rsurface.modelnormal3f_vertexbuffer = 0;
6974                         rsurface.modelnormal3f_bufferoffset = 0;
6975                 }
6976                 else if (wantnormals)
6977                 {
6978                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
6979                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
6980                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
6981                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
6982                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6983                         rsurface.modelsvector3f = NULL;
6984                         rsurface.modeltvector3f = NULL;
6985                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6986                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
6987                         rsurface.modelvertex3f_vertexbuffer = NULL;
6988                         rsurface.modelvertex3f_bufferoffset = 0;
6989                         rsurface.modelvertex3f_vertexbuffer = 0;
6990                         rsurface.modelvertex3f_bufferoffset = 0;
6991                         rsurface.modelsvector3f_vertexbuffer = 0;
6992                         rsurface.modelsvector3f_bufferoffset = 0;
6993                         rsurface.modeltvector3f_vertexbuffer = 0;
6994                         rsurface.modeltvector3f_bufferoffset = 0;
6995                         rsurface.modelnormal3f_vertexbuffer = 0;
6996                         rsurface.modelnormal3f_bufferoffset = 0;
6997                 }
6998                 else
6999                 {
7000                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7001                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7002                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7003                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7004                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7005                         rsurface.modelsvector3f = NULL;
7006                         rsurface.modeltvector3f = NULL;
7007                         rsurface.modelnormal3f = NULL;
7008                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7009                         rsurface.modelvertex3f_vertexbuffer = NULL;
7010                         rsurface.modelvertex3f_bufferoffset = 0;
7011                         rsurface.modelvertex3f_vertexbuffer = 0;
7012                         rsurface.modelvertex3f_bufferoffset = 0;
7013                         rsurface.modelsvector3f_vertexbuffer = 0;
7014                         rsurface.modelsvector3f_bufferoffset = 0;
7015                         rsurface.modeltvector3f_vertexbuffer = 0;
7016                         rsurface.modeltvector3f_bufferoffset = 0;
7017                         rsurface.modelnormal3f_vertexbuffer = 0;
7018                         rsurface.modelnormal3f_bufferoffset = 0;
7019                 }
7020                 rsurface.modelgeneratedvertex = true;
7021         }
7022         else
7023         {
7024                 if (rsurface.entityskeletaltransform3x4)
7025                 {
7026                         r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7027                         r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7028                         r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7029                         r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7030                 }
7031                 else
7032                 {
7033                         r_refdef.stats[r_stat_batch_entitystatic_count]++;
7034                         r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7035                         r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7036                         r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7037                 }
7038                 rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
7039                 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.data_vertex3f_vertexbuffer;
7040                 rsurface.modelvertex3f_bufferoffset = model->surfmesh.data_vertex3f_bufferoffset;
7041                 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7042                 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.data_svector3f_vertexbuffer;
7043                 rsurface.modelsvector3f_bufferoffset = model->surfmesh.data_svector3f_bufferoffset;
7044                 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7045                 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.data_tvector3f_vertexbuffer;
7046                 rsurface.modeltvector3f_bufferoffset = model->surfmesh.data_tvector3f_bufferoffset;
7047                 rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
7048                 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.data_normal3f_vertexbuffer;
7049                 rsurface.modelnormal3f_bufferoffset = model->surfmesh.data_normal3f_bufferoffset;
7050                 rsurface.modelgeneratedvertex = false;
7051         }
7052         rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
7053         rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.data_lightmapcolor4f_vertexbuffer;
7054         rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.data_lightmapcolor4f_bufferoffset;
7055         rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
7056         rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.data_texcoordtexture2f_vertexbuffer;
7057         rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.data_texcoordtexture2f_bufferoffset;
7058         rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
7059         rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.data_texcoordlightmap2f_vertexbuffer;
7060         rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.data_texcoordlightmap2f_bufferoffset;
7061         rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7062         rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.data_skeletalindex4ub_vertexbuffer;
7063         rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.data_skeletalindex4ub_bufferoffset;
7064         rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7065         rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.data_skeletalweight4ub_vertexbuffer;
7066         rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.data_skeletalweight4ub_bufferoffset;
7067         rsurface.modelelement3i = model->surfmesh.data_element3i;
7068         rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7069         rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7070         rsurface.modelelement3s = model->surfmesh.data_element3s;
7071         rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7072         rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7073         rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7074         rsurface.modelnumvertices = model->surfmesh.num_vertices;
7075         rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7076         rsurface.modelsurfaces = model->data_surfaces;
7077         rsurface.batchgeneratedvertex = false;
7078         rsurface.batchfirstvertex = 0;
7079         rsurface.batchnumvertices = 0;
7080         rsurface.batchfirsttriangle = 0;
7081         rsurface.batchnumtriangles = 0;
7082         rsurface.batchvertex3f  = NULL;
7083         rsurface.batchvertex3f_vertexbuffer = NULL;
7084         rsurface.batchvertex3f_bufferoffset = 0;
7085         rsurface.batchsvector3f = NULL;
7086         rsurface.batchsvector3f_vertexbuffer = NULL;
7087         rsurface.batchsvector3f_bufferoffset = 0;
7088         rsurface.batchtvector3f = NULL;
7089         rsurface.batchtvector3f_vertexbuffer = NULL;
7090         rsurface.batchtvector3f_bufferoffset = 0;
7091         rsurface.batchnormal3f  = NULL;
7092         rsurface.batchnormal3f_vertexbuffer = NULL;
7093         rsurface.batchnormal3f_bufferoffset = 0;
7094         rsurface.batchlightmapcolor4f = NULL;
7095         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7096         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7097         rsurface.batchtexcoordtexture2f = NULL;
7098         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7099         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7100         rsurface.batchtexcoordlightmap2f = NULL;
7101         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7102         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7103         rsurface.batchskeletalindex4ub = NULL;
7104         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7105         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7106         rsurface.batchskeletalweight4ub = NULL;
7107         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7108         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7109         rsurface.batchelement3i = NULL;
7110         rsurface.batchelement3i_indexbuffer = NULL;
7111         rsurface.batchelement3i_bufferoffset = 0;
7112         rsurface.batchelement3s = NULL;
7113         rsurface.batchelement3s_indexbuffer = NULL;
7114         rsurface.batchelement3s_bufferoffset = 0;
7115         rsurface.forcecurrenttextureupdate = false;
7116 }
7117
7118 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)
7119 {
7120         rsurface.entity = r_refdef.scene.worldentity;
7121         if (r != 1.0f || g != 1.0f || b != 1.0f || a != 1.0f) {
7122                 // HACK to provide a valid entity with modded colors to R_GetCurrentTexture.
7123                 // A better approach could be making this copy only once per frame.
7124                 static entity_render_t custom_entity;
7125                 int q;
7126                 custom_entity = *rsurface.entity;
7127                 for (q = 0; q < 3; ++q) {
7128                         float colormod = q == 0 ? r : q == 1 ? g : b;
7129                         custom_entity.render_fullbright[q] *= colormod;
7130                         custom_entity.render_modellight_ambient[q] *= colormod;
7131                         custom_entity.render_modellight_diffuse[q] *= colormod;
7132                         custom_entity.render_lightmap_ambient[q] *= colormod;
7133                         custom_entity.render_lightmap_diffuse[q] *= colormod;
7134                         custom_entity.render_rtlight_diffuse[q] *= colormod;
7135                 }
7136                 custom_entity.alpha *= a;
7137                 rsurface.entity = &custom_entity;
7138         }
7139         rsurface.skeleton = NULL;
7140         rsurface.ent_skinnum = 0;
7141         rsurface.ent_qwskin = -1;
7142         rsurface.ent_flags = entflags;
7143         rsurface.shadertime = r_refdef.scene.time - shadertime;
7144         rsurface.modelnumvertices = numvertices;
7145         rsurface.modelnumtriangles = numtriangles;
7146         rsurface.matrix = *matrix;
7147         rsurface.inversematrix = *inversematrix;
7148         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7149         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7150         R_EntityMatrix(&rsurface.matrix);
7151         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7152         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7153         rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7154         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7155         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7156         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7157         memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7158         rsurface.frameblend[0].lerp = 1;
7159         rsurface.ent_alttextures = false;
7160         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7161         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7162         rsurface.entityskeletaltransform3x4 = NULL;
7163         rsurface.entityskeletaltransform3x4buffer = NULL;
7164         rsurface.entityskeletaltransform3x4offset = 0;
7165         rsurface.entityskeletaltransform3x4size = 0;
7166         rsurface.entityskeletalnumtransforms = 0;
7167         r_refdef.stats[r_stat_batch_entitycustom_count]++;
7168         r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7169         r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7170         r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7171         if (wanttangents)
7172         {
7173                 rsurface.modelvertex3f = (float *)vertex3f;
7174                 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7175                 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7176                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7177         }
7178         else if (wantnormals)
7179         {
7180                 rsurface.modelvertex3f = (float *)vertex3f;
7181                 rsurface.modelsvector3f = NULL;
7182                 rsurface.modeltvector3f = NULL;
7183                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7184         }
7185         else
7186         {
7187                 rsurface.modelvertex3f = (float *)vertex3f;
7188                 rsurface.modelsvector3f = NULL;
7189                 rsurface.modeltvector3f = NULL;
7190                 rsurface.modelnormal3f = NULL;
7191         }
7192         rsurface.modelvertex3f_vertexbuffer = 0;
7193         rsurface.modelvertex3f_bufferoffset = 0;
7194         rsurface.modelsvector3f_vertexbuffer = 0;
7195         rsurface.modelsvector3f_bufferoffset = 0;
7196         rsurface.modeltvector3f_vertexbuffer = 0;
7197         rsurface.modeltvector3f_bufferoffset = 0;
7198         rsurface.modelnormal3f_vertexbuffer = 0;
7199         rsurface.modelnormal3f_bufferoffset = 0;
7200         rsurface.modelgeneratedvertex = true;
7201         rsurface.modellightmapcolor4f  = (float *)color4f;
7202         rsurface.modellightmapcolor4f_vertexbuffer = 0;
7203         rsurface.modellightmapcolor4f_bufferoffset = 0;
7204         rsurface.modeltexcoordtexture2f  = (float *)texcoord2f;
7205         rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7206         rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7207         rsurface.modeltexcoordlightmap2f  = NULL;
7208         rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7209         rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7210         rsurface.modelskeletalindex4ub = NULL;
7211         rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7212         rsurface.modelskeletalindex4ub_bufferoffset = 0;
7213         rsurface.modelskeletalweight4ub = NULL;
7214         rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7215         rsurface.modelskeletalweight4ub_bufferoffset = 0;
7216         rsurface.modelelement3i = (int *)element3i;
7217         rsurface.modelelement3i_indexbuffer = NULL;
7218         rsurface.modelelement3i_bufferoffset = 0;
7219         rsurface.modelelement3s = (unsigned short *)element3s;
7220         rsurface.modelelement3s_indexbuffer = NULL;
7221         rsurface.modelelement3s_bufferoffset = 0;
7222         rsurface.modellightmapoffsets = NULL;
7223         rsurface.modelsurfaces = NULL;
7224         rsurface.batchgeneratedvertex = false;
7225         rsurface.batchfirstvertex = 0;
7226         rsurface.batchnumvertices = 0;
7227         rsurface.batchfirsttriangle = 0;
7228         rsurface.batchnumtriangles = 0;
7229         rsurface.batchvertex3f  = NULL;
7230         rsurface.batchvertex3f_vertexbuffer = NULL;
7231         rsurface.batchvertex3f_bufferoffset = 0;
7232         rsurface.batchsvector3f = NULL;
7233         rsurface.batchsvector3f_vertexbuffer = NULL;
7234         rsurface.batchsvector3f_bufferoffset = 0;
7235         rsurface.batchtvector3f = NULL;
7236         rsurface.batchtvector3f_vertexbuffer = NULL;
7237         rsurface.batchtvector3f_bufferoffset = 0;
7238         rsurface.batchnormal3f  = NULL;
7239         rsurface.batchnormal3f_vertexbuffer = NULL;
7240         rsurface.batchnormal3f_bufferoffset = 0;
7241         rsurface.batchlightmapcolor4f = NULL;
7242         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7243         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7244         rsurface.batchtexcoordtexture2f = NULL;
7245         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7246         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7247         rsurface.batchtexcoordlightmap2f = NULL;
7248         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7249         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7250         rsurface.batchskeletalindex4ub = NULL;
7251         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7252         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7253         rsurface.batchskeletalweight4ub = NULL;
7254         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7255         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7256         rsurface.batchelement3i = NULL;
7257         rsurface.batchelement3i_indexbuffer = NULL;
7258         rsurface.batchelement3i_bufferoffset = 0;
7259         rsurface.batchelement3s = NULL;
7260         rsurface.batchelement3s_indexbuffer = NULL;
7261         rsurface.batchelement3s_bufferoffset = 0;
7262         rsurface.forcecurrenttextureupdate = true;
7263
7264         if (rsurface.modelnumvertices && rsurface.modelelement3i)
7265         {
7266                 if ((wantnormals || wanttangents) && !normal3f)
7267                 {
7268                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7269                         Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7270                 }
7271                 if (wanttangents && !svector3f)
7272                 {
7273                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7274                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7275                         Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7276                 }
7277         }
7278 }
7279
7280 float RSurf_FogPoint(const float *v)
7281 {
7282         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7283         float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7284         float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7285         float FogHeightFade = r_refdef.fogheightfade;
7286         float fogfrac;
7287         unsigned int fogmasktableindex;
7288         if (r_refdef.fogplaneviewabove)
7289                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7290         else
7291                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7292         fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7293         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7294 }
7295
7296 float RSurf_FogVertex(const float *v)
7297 {
7298         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7299         float FogPlaneViewDist = rsurface.fogplaneviewdist;
7300         float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7301         float FogHeightFade = rsurface.fogheightfade;
7302         float fogfrac;
7303         unsigned int fogmasktableindex;
7304         if (r_refdef.fogplaneviewabove)
7305                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7306         else
7307                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7308         fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7309         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7310 }
7311
7312 void RSurf_UploadBuffersForBatch(void)
7313 {
7314         // 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)
7315         // note that if rsurface.batchvertex3f_vertexbuffer is NULL, dynamicvertex is forced as we don't account for the proper base vertex here.
7316         if (rsurface.batchvertex3f && !rsurface.batchvertex3f_vertexbuffer)
7317                 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
7318         if (rsurface.batchsvector3f && !rsurface.batchsvector3f_vertexbuffer)
7319                 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
7320         if (rsurface.batchtvector3f && !rsurface.batchtvector3f_vertexbuffer)
7321                 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
7322         if (rsurface.batchnormal3f && !rsurface.batchnormal3f_vertexbuffer)
7323                 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
7324         if (rsurface.batchlightmapcolor4f && !rsurface.batchlightmapcolor4f_vertexbuffer)
7325                 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
7326         if (rsurface.batchtexcoordtexture2f && !rsurface.batchtexcoordtexture2f_vertexbuffer)
7327                 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
7328         if (rsurface.batchtexcoordlightmap2f && !rsurface.batchtexcoordlightmap2f_vertexbuffer)
7329                 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
7330         if (rsurface.batchskeletalindex4ub && !rsurface.batchskeletalindex4ub_vertexbuffer)
7331                 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
7332         if (rsurface.batchskeletalweight4ub && !rsurface.batchskeletalweight4ub_vertexbuffer)
7333                 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
7334
7335         if (rsurface.batchelement3s && !rsurface.batchelement3s_indexbuffer)
7336                 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
7337         else if (rsurface.batchelement3i && !rsurface.batchelement3i_indexbuffer)
7338                 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
7339
7340         R_Mesh_VertexPointer(     3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
7341         R_Mesh_ColorPointer(      4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
7342         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
7343         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
7344         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
7345         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
7346         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
7347         R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
7348         R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
7349         R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
7350 }
7351
7352 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7353 {
7354         int i;
7355         for (i = 0;i < numelements;i++)
7356                 outelement3i[i] = inelement3i[i] + adjust;
7357 }
7358
7359 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7360 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7361 {
7362         int deformindex;
7363         int firsttriangle;
7364         int numtriangles;
7365         int firstvertex;
7366         int endvertex;
7367         int numvertices;
7368         int surfacefirsttriangle;
7369         int surfacenumtriangles;
7370         int surfacefirstvertex;
7371         int surfaceendvertex;
7372         int surfacenumvertices;
7373         int batchnumsurfaces = texturenumsurfaces;
7374         int batchnumvertices;
7375         int batchnumtriangles;
7376         int i, j;
7377         qboolean gaps;
7378         qboolean dynamicvertex;
7379         float amplitude;
7380         float animpos;
7381         float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7382         float waveparms[4];
7383         unsigned char *ub;
7384         q3shaderinfo_deform_t *deform;
7385         const msurface_t *surface, *firstsurface;
7386         if (!texturenumsurfaces)
7387                 return;
7388         // find vertex range of this surface batch
7389         gaps = false;
7390         firstsurface = texturesurfacelist[0];
7391         firsttriangle = firstsurface->num_firsttriangle;
7392         batchnumvertices = 0;
7393         batchnumtriangles = 0;
7394         firstvertex = endvertex = firstsurface->num_firstvertex;
7395         for (i = 0;i < texturenumsurfaces;i++)
7396         {
7397                 surface = texturesurfacelist[i];
7398                 if (surface != firstsurface + i)
7399                         gaps = true;
7400                 surfacefirstvertex = surface->num_firstvertex;
7401                 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7402                 surfacenumvertices = surface->num_vertices;
7403                 surfacenumtriangles = surface->num_triangles;
7404                 if (firstvertex > surfacefirstvertex)
7405                         firstvertex = surfacefirstvertex;
7406                 if (endvertex < surfaceendvertex)
7407                         endvertex = surfaceendvertex;
7408                 batchnumvertices += surfacenumvertices;
7409                 batchnumtriangles += surfacenumtriangles;
7410         }
7411
7412         r_refdef.stats[r_stat_batch_batches]++;
7413         if (gaps)
7414                 r_refdef.stats[r_stat_batch_withgaps]++;
7415         r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7416         r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7417         r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7418
7419         // we now know the vertex range used, and if there are any gaps in it
7420         rsurface.batchfirstvertex = firstvertex;
7421         rsurface.batchnumvertices = endvertex - firstvertex;
7422         rsurface.batchfirsttriangle = firsttriangle;
7423         rsurface.batchnumtriangles = batchnumtriangles;
7424
7425         // check if any dynamic vertex processing must occur
7426         dynamicvertex = false;
7427
7428         // we must use vertexbuffers for rendering, we can upload vertex buffers
7429         // easily enough but if the basevertex is non-zero it becomes more
7430         // difficult, so force dynamicvertex path in that case - it's suboptimal
7431         // but the most optimal case is to have the geometry sources provide their
7432         // own anyway.
7433         if (!rsurface.modelvertex3f_vertexbuffer && firstvertex != 0)
7434                 dynamicvertex = true;
7435
7436         // a cvar to force the dynamic vertex path to be taken, for debugging
7437         if (r_batch_debugdynamicvertexpath.integer)
7438         {
7439                 if (!dynamicvertex)
7440                 {
7441                         r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7442                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7443                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7444                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7445                 }
7446                 dynamicvertex = true;
7447         }
7448
7449         // if there is a chance of animated vertex colors, it's a dynamic batch
7450         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
7451         {
7452                 if (!dynamicvertex)
7453                 {
7454                         r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7455                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7456                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7457                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7458                 }
7459                 dynamicvertex = true;
7460         }
7461
7462         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7463         {
7464                 switch (deform->deform)
7465                 {
7466                 default:
7467                 case Q3DEFORM_PROJECTIONSHADOW:
7468                 case Q3DEFORM_TEXT0:
7469                 case Q3DEFORM_TEXT1:
7470                 case Q3DEFORM_TEXT2:
7471                 case Q3DEFORM_TEXT3:
7472                 case Q3DEFORM_TEXT4:
7473                 case Q3DEFORM_TEXT5:
7474                 case Q3DEFORM_TEXT6:
7475                 case Q3DEFORM_TEXT7:
7476                 case Q3DEFORM_NONE:
7477                         break;
7478                 case Q3DEFORM_AUTOSPRITE:
7479                         if (!dynamicvertex)
7480                         {
7481                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7482                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7483                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7484                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7485                         }
7486                         dynamicvertex = true;
7487                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7488                         break;
7489                 case Q3DEFORM_AUTOSPRITE2:
7490                         if (!dynamicvertex)
7491                         {
7492                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7493                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7494                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7495                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7496                         }
7497                         dynamicvertex = true;
7498                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7499                         break;
7500                 case Q3DEFORM_NORMAL:
7501                         if (!dynamicvertex)
7502                         {
7503                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7504                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7505                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7506                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7507                         }
7508                         dynamicvertex = true;
7509                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7510                         break;
7511                 case Q3DEFORM_WAVE:
7512                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7513                                 break; // if wavefunc is a nop, ignore this transform
7514                         if (!dynamicvertex)
7515                         {
7516                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7517                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7518                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7519                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7520                         }
7521                         dynamicvertex = true;
7522                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7523                         break;
7524                 case Q3DEFORM_BULGE:
7525                         if (!dynamicvertex)
7526                         {
7527                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7528                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7529                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7530                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7531                         }
7532                         dynamicvertex = true;
7533                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7534                         break;
7535                 case Q3DEFORM_MOVE:
7536                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7537                                 break; // if wavefunc is a nop, ignore this transform
7538                         if (!dynamicvertex)
7539                         {
7540                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7541                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7542                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7543                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7544                         }
7545                         dynamicvertex = true;
7546                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7547                         break;
7548                 }
7549         }
7550         if (rsurface.texture->materialshaderpass)
7551         {
7552                 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7553                 {
7554                 default:
7555                 case Q3TCGEN_TEXTURE:
7556                         break;
7557                 case Q3TCGEN_LIGHTMAP:
7558                         if (!dynamicvertex)
7559                         {
7560                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7561                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7562                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7563                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7564                         }
7565                         dynamicvertex = true;
7566                         batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7567                         break;
7568                 case Q3TCGEN_VECTOR:
7569                         if (!dynamicvertex)
7570                         {
7571                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7572                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7573                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7574                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7575                         }
7576                         dynamicvertex = true;
7577                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7578                         break;
7579                 case Q3TCGEN_ENVIRONMENT:
7580                         if (!dynamicvertex)
7581                         {
7582                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7583                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7584                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7585                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7586                         }
7587                         dynamicvertex = true;
7588                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7589                         break;
7590                 }
7591                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7592                 {
7593                         if (!dynamicvertex)
7594                         {
7595                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7596                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7597                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7598                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7599                         }
7600                         dynamicvertex = true;
7601                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7602                 }
7603         }
7604
7605         // the caller can specify BATCHNEED_NOGAPS to force a batch with
7606         // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7607         // we ensure this by treating the vertex batch as dynamic...
7608         if ((batchneed & BATCHNEED_ALWAYSCOPY) || ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0)))
7609         {
7610                 if (!dynamicvertex)
7611                 {
7612                         r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7613                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7614                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7615                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7616                 }
7617                 dynamicvertex = true;
7618         }
7619
7620         // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7621         if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7622                 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7623
7624         rsurface.batchvertex3f = rsurface.modelvertex3f;
7625         rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7626         rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7627         rsurface.batchsvector3f = rsurface.modelsvector3f;
7628         rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7629         rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7630         rsurface.batchtvector3f = rsurface.modeltvector3f;
7631         rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7632         rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7633         rsurface.batchnormal3f = rsurface.modelnormal3f;
7634         rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7635         rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7636         rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7637         rsurface.batchlightmapcolor4f_vertexbuffer  = rsurface.modellightmapcolor4f_vertexbuffer;
7638         rsurface.batchlightmapcolor4f_bufferoffset  = rsurface.modellightmapcolor4f_bufferoffset;
7639         rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7640         rsurface.batchtexcoordtexture2f_vertexbuffer  = rsurface.modeltexcoordtexture2f_vertexbuffer;
7641         rsurface.batchtexcoordtexture2f_bufferoffset  = rsurface.modeltexcoordtexture2f_bufferoffset;
7642         rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7643         rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7644         rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7645         rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7646         rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7647         rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7648         rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7649         rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7650         rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7651         rsurface.batchelement3i = rsurface.modelelement3i;
7652         rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7653         rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7654         rsurface.batchelement3s = rsurface.modelelement3s;
7655         rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7656         rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7657         rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7658         rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7659         rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7660         rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7661         rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7662
7663         // if any dynamic vertex processing has to occur in software, we copy the
7664         // entire surface list together before processing to rebase the vertices
7665         // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7666         //
7667         // if any gaps exist and we do not have a static vertex buffer, we have to
7668         // copy the surface list together to avoid wasting upload bandwidth on the
7669         // vertices in the gaps.
7670         //
7671         // if gaps exist and we have a static vertex buffer, we can choose whether
7672         // to combine the index buffer ranges into one dynamic index buffer or
7673         // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7674         //
7675         // in many cases the batch is reduced to one draw call.
7676
7677         rsurface.batchmultidraw = false;
7678         rsurface.batchmultidrawnumsurfaces = 0;
7679         rsurface.batchmultidrawsurfacelist = NULL;
7680
7681         if (!dynamicvertex)
7682         {
7683                 // static vertex data, just set pointers...
7684                 rsurface.batchgeneratedvertex = false;
7685                 // if there are gaps, we want to build a combined index buffer,
7686                 // otherwise use the original static buffer with an appropriate offset
7687                 if (gaps)
7688                 {
7689                         r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7690                         r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7691                         r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7692                         r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7693                         if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7694                         {
7695                                 rsurface.batchmultidraw = true;
7696                                 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7697                                 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7698                                 return;
7699                         }
7700                         // build a new triangle elements array for this batch
7701                         rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7702                         rsurface.batchfirsttriangle = 0;
7703                         numtriangles = 0;
7704                         for (i = 0;i < texturenumsurfaces;i++)
7705                         {
7706                                 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7707                                 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7708                                 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7709                                 numtriangles += surfacenumtriangles;
7710                         }
7711                         rsurface.batchelement3i_indexbuffer = NULL;
7712                         rsurface.batchelement3i_bufferoffset = 0;
7713                         rsurface.batchelement3s = NULL;
7714                         rsurface.batchelement3s_indexbuffer = NULL;
7715                         rsurface.batchelement3s_bufferoffset = 0;
7716                         if (endvertex <= 65536)
7717                         {
7718                                 // make a 16bit (unsigned short) index array if possible
7719                                 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7720                                 for (i = 0;i < numtriangles*3;i++)
7721                                         rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7722                         }
7723                 }
7724                 else
7725                 {
7726                         r_refdef.stats[r_stat_batch_fast_batches] += 1;
7727                         r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
7728                         r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
7729                         r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
7730                 }
7731                 return;
7732         }
7733
7734         // something needs software processing, do it for real...
7735         // we only directly handle separate array data in this case and then
7736         // generate interleaved data if needed...
7737         rsurface.batchgeneratedvertex = true;
7738         r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
7739         r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
7740         r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
7741         r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
7742
7743         // now copy the vertex data into a combined array and make an index array
7744         // (this is what Quake3 does all the time)
7745         // we also apply any skeletal animation here that would have been done in
7746         // the vertex shader, because most of the dynamic vertex animation cases
7747         // need actual vertex positions and normals
7748         //if (dynamicvertex)
7749         {
7750                 rsurface.batchvertex3f = NULL;
7751                 rsurface.batchvertex3f_vertexbuffer = NULL;
7752                 rsurface.batchvertex3f_bufferoffset = 0;
7753                 rsurface.batchsvector3f = NULL;
7754                 rsurface.batchsvector3f_vertexbuffer = NULL;
7755                 rsurface.batchsvector3f_bufferoffset = 0;
7756                 rsurface.batchtvector3f = NULL;
7757                 rsurface.batchtvector3f_vertexbuffer = NULL;
7758                 rsurface.batchtvector3f_bufferoffset = 0;
7759                 rsurface.batchnormal3f = NULL;
7760                 rsurface.batchnormal3f_vertexbuffer = NULL;
7761                 rsurface.batchnormal3f_bufferoffset = 0;
7762                 rsurface.batchlightmapcolor4f = NULL;
7763                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7764                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7765                 rsurface.batchtexcoordtexture2f = NULL;
7766                 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7767                 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7768                 rsurface.batchtexcoordlightmap2f = NULL;
7769                 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7770                 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7771                 rsurface.batchskeletalindex4ub = NULL;
7772                 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7773                 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7774                 rsurface.batchskeletalweight4ub = NULL;
7775                 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7776                 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7777                 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7778                 rsurface.batchelement3i_indexbuffer = NULL;
7779                 rsurface.batchelement3i_bufferoffset = 0;
7780                 rsurface.batchelement3s = NULL;
7781                 rsurface.batchelement3s_indexbuffer = NULL;
7782                 rsurface.batchelement3s_bufferoffset = 0;
7783                 rsurface.batchskeletaltransform3x4buffer = NULL;
7784                 rsurface.batchskeletaltransform3x4offset = 0;
7785                 rsurface.batchskeletaltransform3x4size = 0;
7786                 // we'll only be setting up certain arrays as needed
7787                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7788                         rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7789                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7790                         rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7791                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7792                 {
7793                         rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7794                         rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7795                 }
7796                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7797                         rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
7798                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7799                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7800                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7801                         rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7802                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7803                 {
7804                         rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7805                         rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7806                 }
7807                 numvertices = 0;
7808                 numtriangles = 0;
7809                 for (i = 0;i < texturenumsurfaces;i++)
7810                 {
7811                         surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
7812                         surfacenumvertices = texturesurfacelist[i]->num_vertices;
7813                         surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7814                         surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7815                         // copy only the data requested
7816                         if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
7817                         {
7818                                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7819                                 {
7820                                         if (rsurface.batchvertex3f)
7821                                                 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7822                                         else
7823                                                 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7824                                 }
7825                                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7826                                 {
7827                                         if (rsurface.modelnormal3f)
7828                                                 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7829                                         else
7830                                                 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7831                                 }
7832                                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7833                                 {
7834                                         if (rsurface.modelsvector3f)
7835                                         {
7836                                                 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7837                                                 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7838                                         }
7839                                         else
7840                                         {
7841                                                 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7842                                                 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7843                                         }
7844                                 }
7845                                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7846                                 {
7847                                         if (rsurface.modellightmapcolor4f)
7848                                                 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
7849                                         else
7850                                                 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
7851                                 }
7852                                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7853                                 {
7854                                         if (rsurface.modeltexcoordtexture2f)
7855                                                 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7856                                         else
7857                                                 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7858                                 }
7859                                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7860                                 {
7861                                         if (rsurface.modeltexcoordlightmap2f)
7862                                                 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7863                                         else
7864                                                 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7865                                 }
7866                                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7867                                 {
7868                                         if (rsurface.modelskeletalindex4ub)
7869                                         {
7870                                                 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7871                                                 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7872                                         }
7873                                         else
7874                                         {
7875                                                 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7876                                                 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7877                                                 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
7878                                                 for (j = 0;j < surfacenumvertices;j++)
7879                                                         ub[j*4] = 255;
7880                                         }
7881                                 }
7882                         }
7883                         RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
7884                         numvertices += surfacenumvertices;
7885                         numtriangles += surfacenumtriangles;
7886                 }
7887
7888                 // generate a 16bit index array as well if possible
7889                 // (in general, dynamic batches fit)
7890                 if (numvertices <= 65536)
7891                 {
7892                         rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7893                         for (i = 0;i < numtriangles*3;i++)
7894                                 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7895                 }
7896
7897                 // since we've copied everything, the batch now starts at 0
7898                 rsurface.batchfirstvertex = 0;
7899                 rsurface.batchnumvertices = batchnumvertices;
7900                 rsurface.batchfirsttriangle = 0;
7901                 rsurface.batchnumtriangles = batchnumtriangles;
7902         }
7903
7904         // apply skeletal animation that would have been done in the vertex shader
7905         if (rsurface.batchskeletaltransform3x4)
7906         {
7907                 const unsigned char *si;
7908                 const unsigned char *sw;
7909                 const float *t[4];
7910                 const float *b = rsurface.batchskeletaltransform3x4;
7911                 float *vp, *vs, *vt, *vn;
7912                 float w[4];
7913                 float m[3][4], n[3][4];
7914                 float tp[3], ts[3], tt[3], tn[3];
7915                 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
7916                 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
7917                 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
7918                 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
7919                 si = rsurface.batchskeletalindex4ub;
7920                 sw = rsurface.batchskeletalweight4ub;
7921                 vp = rsurface.batchvertex3f;
7922                 vs = rsurface.batchsvector3f;
7923                 vt = rsurface.batchtvector3f;
7924                 vn = rsurface.batchnormal3f;
7925                 memset(m[0], 0, sizeof(m));
7926                 memset(n[0], 0, sizeof(n));
7927                 for (i = 0;i < batchnumvertices;i++)
7928                 {
7929                         t[0] = b + si[0]*12;
7930                         if (sw[0] == 255)
7931                         {
7932                                 // common case - only one matrix
7933                                 m[0][0] = t[0][ 0];
7934                                 m[0][1] = t[0][ 1];
7935                                 m[0][2] = t[0][ 2];
7936                                 m[0][3] = t[0][ 3];
7937                                 m[1][0] = t[0][ 4];
7938                                 m[1][1] = t[0][ 5];
7939                                 m[1][2] = t[0][ 6];
7940                                 m[1][3] = t[0][ 7];
7941                                 m[2][0] = t[0][ 8];
7942                                 m[2][1] = t[0][ 9];
7943                                 m[2][2] = t[0][10];
7944                                 m[2][3] = t[0][11];
7945                         }
7946                         else if (sw[2] + sw[3])
7947                         {
7948                                 // blend 4 matrices
7949                                 t[1] = b + si[1]*12;
7950                                 t[2] = b + si[2]*12;
7951                                 t[3] = b + si[3]*12;
7952                                 w[0] = sw[0] * (1.0f / 255.0f);
7953                                 w[1] = sw[1] * (1.0f / 255.0f);
7954                                 w[2] = sw[2] * (1.0f / 255.0f);
7955                                 w[3] = sw[3] * (1.0f / 255.0f);
7956                                 // blend the matrices
7957                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
7958                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
7959                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
7960                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
7961                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
7962                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
7963                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
7964                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
7965                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
7966                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
7967                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
7968                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
7969                         }
7970                         else
7971                         {
7972                                 // blend 2 matrices
7973                                 t[1] = b + si[1]*12;
7974                                 w[0] = sw[0] * (1.0f / 255.0f);
7975                                 w[1] = sw[1] * (1.0f / 255.0f);
7976                                 // blend the matrices
7977                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
7978                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
7979                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
7980                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
7981                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
7982                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
7983                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
7984                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
7985                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
7986                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
7987                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
7988                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
7989                         }
7990                         si += 4;
7991                         sw += 4;
7992                         // modify the vertex
7993                         VectorCopy(vp, tp);
7994                         vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
7995                         vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
7996                         vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
7997                         vp += 3;
7998                         if (vn)
7999                         {
8000                                 // the normal transformation matrix is a set of cross products...
8001                                 CrossProduct(m[1], m[2], n[0]);
8002                                 CrossProduct(m[2], m[0], n[1]);
8003                                 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8004                                 VectorCopy(vn, tn);
8005                                 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8006                                 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8007                                 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8008                                 VectorNormalize(vn);
8009                                 vn += 3;
8010                                 if (vs)
8011                                 {
8012                                         VectorCopy(vs, ts);
8013                                         vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8014                                         vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8015                                         vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8016                                         VectorNormalize(vs);
8017                                         vs += 3;
8018                                         VectorCopy(vt, tt);
8019                                         vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8020                                         vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8021                                         vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8022                                         VectorNormalize(vt);
8023                                         vt += 3;
8024                                 }
8025                         }
8026                 }
8027                 rsurface.batchskeletaltransform3x4 = NULL;
8028                 rsurface.batchskeletalnumtransforms = 0;
8029         }
8030
8031         // q1bsp surfaces rendered in vertex color mode have to have colors
8032         // calculated based on lightstyles
8033         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
8034         {
8035                 // generate color arrays for the surfaces in this list
8036                 int c[4];
8037                 int scale;
8038                 int size3;
8039                 const int *offsets;
8040                 const unsigned char *lm;
8041                 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8042                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8043                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8044                 numvertices = 0;
8045                 for (i = 0;i < texturenumsurfaces;i++)
8046                 {
8047                         surface = texturesurfacelist[i];
8048                         offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8049                         surfacenumvertices = surface->num_vertices;
8050                         if (surface->lightmapinfo->samples)
8051                         {
8052                                 for (j = 0;j < surfacenumvertices;j++)
8053                                 {
8054                                         lm = surface->lightmapinfo->samples + offsets[j];
8055                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8056                                         VectorScale(lm, scale, c);
8057                                         if (surface->lightmapinfo->styles[1] != 255)
8058                                         {
8059                                                 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8060                                                 lm += size3;
8061                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8062                                                 VectorMA(c, scale, lm, c);
8063                                                 if (surface->lightmapinfo->styles[2] != 255)
8064                                                 {
8065                                                         lm += size3;
8066                                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8067                                                         VectorMA(c, scale, lm, c);
8068                                                         if (surface->lightmapinfo->styles[3] != 255)
8069                                                         {
8070                                                                 lm += size3;
8071                                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8072                                                                 VectorMA(c, scale, lm, c);
8073                                                         }
8074                                                 }
8075                                         }
8076                                         c[0] >>= 7;
8077                                         c[1] >>= 7;
8078                                         c[2] >>= 7;
8079                                         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);
8080                                         numvertices++;
8081                                 }
8082                         }
8083                         else
8084                         {
8085                                 for (j = 0;j < surfacenumvertices;j++)
8086                                 {
8087                                         Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8088                                         numvertices++;
8089                                 }
8090                         }
8091                 }
8092         }
8093
8094         // if vertices are deformed (sprite flares and things in maps, possibly
8095         // water waves, bulges and other deformations), modify the copied vertices
8096         // in place
8097         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8098         {
8099                 float scale;
8100                 switch (deform->deform)
8101                 {
8102                 default:
8103                 case Q3DEFORM_PROJECTIONSHADOW:
8104                 case Q3DEFORM_TEXT0:
8105                 case Q3DEFORM_TEXT1:
8106                 case Q3DEFORM_TEXT2:
8107                 case Q3DEFORM_TEXT3:
8108                 case Q3DEFORM_TEXT4:
8109                 case Q3DEFORM_TEXT5:
8110                 case Q3DEFORM_TEXT6:
8111                 case Q3DEFORM_TEXT7:
8112                 case Q3DEFORM_NONE:
8113                         break;
8114                 case Q3DEFORM_AUTOSPRITE:
8115                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8116                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8117                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8118                         VectorNormalize(newforward);
8119                         VectorNormalize(newright);
8120                         VectorNormalize(newup);
8121 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8122 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8123 //                      rsurface.batchvertex3f_bufferoffset = 0;
8124 //                      rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8125 //                      rsurface.batchsvector3f_vertexbuffer = NULL;
8126 //                      rsurface.batchsvector3f_bufferoffset = 0;
8127 //                      rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8128 //                      rsurface.batchtvector3f_vertexbuffer = NULL;
8129 //                      rsurface.batchtvector3f_bufferoffset = 0;
8130 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8131 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8132 //                      rsurface.batchnormal3f_bufferoffset = 0;
8133                         // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8134                         if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8135                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8136                         if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8137                                 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);
8138                         // a single autosprite surface can contain multiple sprites...
8139                         for (j = 0;j < batchnumvertices - 3;j += 4)
8140                         {
8141                                 VectorClear(center);
8142                                 for (i = 0;i < 4;i++)
8143                                         VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8144                                 VectorScale(center, 0.25f, center);
8145                                 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8146                                 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8147                                 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8148                                 for (i = 0;i < 4;i++)
8149                                 {
8150                                         VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8151                                         VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8152                                 }
8153                         }
8154                         // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8155                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8156                         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);
8157                         break;
8158                 case Q3DEFORM_AUTOSPRITE2:
8159                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8160                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8161                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8162                         VectorNormalize(newforward);
8163                         VectorNormalize(newright);
8164                         VectorNormalize(newup);
8165 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8166 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8167 //                      rsurface.batchvertex3f_bufferoffset = 0;
8168                         {
8169                                 const float *v1, *v2;
8170                                 vec3_t start, end;
8171                                 float f, l;
8172                                 struct
8173                                 {
8174                                         float length2;
8175                                         const float *v1;
8176                                         const float *v2;
8177                                 }
8178                                 shortest[2];
8179                                 memset(shortest, 0, sizeof(shortest));
8180                                 // a single autosprite surface can contain multiple sprites...
8181                                 for (j = 0;j < batchnumvertices - 3;j += 4)
8182                                 {
8183                                         VectorClear(center);
8184                                         for (i = 0;i < 4;i++)
8185                                                 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8186                                         VectorScale(center, 0.25f, center);
8187                                         // find the two shortest edges, then use them to define the
8188                                         // axis vectors for rotating around the central axis
8189                                         for (i = 0;i < 6;i++)
8190                                         {
8191                                                 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8192                                                 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8193                                                 l = VectorDistance2(v1, v2);
8194                                                 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8195                                                 if (v1[2] != v2[2])
8196                                                         l += (1.0f / 1024.0f);
8197                                                 if (shortest[0].length2 > l || i == 0)
8198                                                 {
8199                                                         shortest[1] = shortest[0];
8200                                                         shortest[0].length2 = l;
8201                                                         shortest[0].v1 = v1;
8202                                                         shortest[0].v2 = v2;
8203                                                 }
8204                                                 else if (shortest[1].length2 > l || i == 1)
8205                                                 {
8206                                                         shortest[1].length2 = l;
8207                                                         shortest[1].v1 = v1;
8208                                                         shortest[1].v2 = v2;
8209                                                 }
8210                                         }
8211                                         VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8212                                         VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8213                                         // this calculates the right vector from the shortest edge
8214                                         // and the up vector from the edge midpoints
8215                                         VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8216                                         VectorNormalize(right);
8217                                         VectorSubtract(end, start, up);
8218                                         VectorNormalize(up);
8219                                         // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8220                                         VectorSubtract(rsurface.localvieworigin, center, forward);
8221                                         //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8222                                         VectorNegate(forward, forward);
8223                                         VectorReflect(forward, 0, up, forward);
8224                                         VectorNormalize(forward);
8225                                         CrossProduct(up, forward, newright);
8226                                         VectorNormalize(newright);
8227                                         // rotate the quad around the up axis vector, this is made
8228                                         // especially easy by the fact we know the quad is flat,
8229                                         // so we only have to subtract the center position and
8230                                         // measure distance along the right vector, and then
8231                                         // multiply that by the newright vector and add back the
8232                                         // center position
8233                                         // we also need to subtract the old position to undo the
8234                                         // displacement from the center, which we do with a
8235                                         // DotProduct, the subtraction/addition of center is also
8236                                         // optimized into DotProducts here
8237                                         l = DotProduct(right, center);
8238                                         for (i = 0;i < 4;i++)
8239                                         {
8240                                                 v1 = rsurface.batchvertex3f + 3*(j+i);
8241                                                 f = DotProduct(right, v1) - l;
8242                                                 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8243                                         }
8244                                 }
8245                         }
8246                         if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8247                         {
8248 //                              rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8249 //                              rsurface.batchnormal3f_vertexbuffer = NULL;
8250 //                              rsurface.batchnormal3f_bufferoffset = 0;
8251                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8252                         }
8253                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8254                         {
8255 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8256 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8257 //                              rsurface.batchsvector3f_bufferoffset = 0;
8258 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8259 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8260 //                              rsurface.batchtvector3f_bufferoffset = 0;
8261                                 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);
8262                         }
8263                         break;
8264                 case Q3DEFORM_NORMAL:
8265                         // deform the normals to make reflections wavey
8266                         rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8267                         rsurface.batchnormal3f_vertexbuffer = NULL;
8268                         rsurface.batchnormal3f_bufferoffset = 0;
8269                         for (j = 0;j < batchnumvertices;j++)
8270                         {
8271                                 float vertex[3];
8272                                 float *normal = rsurface.batchnormal3f + 3*j;
8273                                 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8274                                 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8275                                 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8276                                 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8277                                 VectorNormalize(normal);
8278                         }
8279                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8280                         {
8281 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8282 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8283 //                              rsurface.batchsvector3f_bufferoffset = 0;
8284 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8285 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8286 //                              rsurface.batchtvector3f_bufferoffset = 0;
8287                                 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);
8288                         }
8289                         break;
8290                 case Q3DEFORM_WAVE:
8291                         // deform vertex array to make wavey water and flags and such
8292                         waveparms[0] = deform->waveparms[0];
8293                         waveparms[1] = deform->waveparms[1];
8294                         waveparms[2] = deform->waveparms[2];
8295                         waveparms[3] = deform->waveparms[3];
8296                         if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8297                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8298                         // this is how a divisor of vertex influence on deformation
8299                         animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8300                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8301 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8302 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8303 //                      rsurface.batchvertex3f_bufferoffset = 0;
8304 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8305 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8306 //                      rsurface.batchnormal3f_bufferoffset = 0;
8307                         for (j = 0;j < batchnumvertices;j++)
8308                         {
8309                                 // if the wavefunc depends on time, evaluate it per-vertex
8310                                 if (waveparms[3])
8311                                 {
8312                                         waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8313                                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8314                                 }
8315                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8316                         }
8317                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8318                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8319                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8320                         {
8321 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8322 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8323 //                              rsurface.batchsvector3f_bufferoffset = 0;
8324 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8325 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8326 //                              rsurface.batchtvector3f_bufferoffset = 0;
8327                                 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);
8328                         }
8329                         break;
8330                 case Q3DEFORM_BULGE:
8331                         // deform vertex array to make the surface have moving bulges
8332 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8333 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8334 //                      rsurface.batchvertex3f_bufferoffset = 0;
8335 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8336 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8337 //                      rsurface.batchnormal3f_bufferoffset = 0;
8338                         for (j = 0;j < batchnumvertices;j++)
8339                         {
8340                                 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8341                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8342                         }
8343                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8344                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8345                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8346                         {
8347 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8348 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8349 //                              rsurface.batchsvector3f_bufferoffset = 0;
8350 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8351 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8352 //                              rsurface.batchtvector3f_bufferoffset = 0;
8353                                 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);
8354                         }
8355                         break;
8356                 case Q3DEFORM_MOVE:
8357                         // deform vertex array
8358                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8359                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8360                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8361                         VectorScale(deform->parms, scale, waveparms);
8362 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8363 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8364 //                      rsurface.batchvertex3f_bufferoffset = 0;
8365                         for (j = 0;j < batchnumvertices;j++)
8366                                 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8367                         break;
8368                 }
8369         }
8370
8371         if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8372         {
8373         // generate texcoords based on the chosen texcoord source
8374                 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8375                 {
8376                 default:
8377                 case Q3TCGEN_TEXTURE:
8378                         break;
8379                 case Q3TCGEN_LIGHTMAP:
8380         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8381         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8382         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8383                         if (rsurface.batchtexcoordlightmap2f)
8384                                 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8385                         break;
8386                 case Q3TCGEN_VECTOR:
8387         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8388         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8389         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8390                         for (j = 0;j < batchnumvertices;j++)
8391                         {
8392                                 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8393                                 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8394                         }
8395                         break;
8396                 case Q3TCGEN_ENVIRONMENT:
8397                         // make environment reflections using a spheremap
8398                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8399                         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8400                         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8401                         for (j = 0;j < batchnumvertices;j++)
8402                         {
8403                                 // identical to Q3A's method, but executed in worldspace so
8404                                 // carried models can be shiny too
8405
8406                                 float viewer[3], d, reflected[3], worldreflected[3];
8407
8408                                 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8409                                 // VectorNormalize(viewer);
8410
8411                                 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8412
8413                                 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8414                                 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8415                                 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8416                                 // note: this is proportinal to viewer, so we can normalize later
8417
8418                                 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8419                                 VectorNormalize(worldreflected);
8420
8421                                 // note: this sphere map only uses world x and z!
8422                                 // so positive and negative y will LOOK THE SAME.
8423                                 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8424                                 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8425                         }
8426                         break;
8427                 }
8428                 // the only tcmod that needs software vertex processing is turbulent, so
8429                 // check for it here and apply the changes if needed
8430                 // and we only support that as the first one
8431                 // (handling a mixture of turbulent and other tcmods would be problematic
8432                 //  without punting it entirely to a software path)
8433                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8434                 {
8435                         amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8436                         animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8437         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8438         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8439         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8440                         for (j = 0;j < batchnumvertices;j++)
8441                         {
8442                                 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);
8443                                 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8444                         }
8445                 }
8446         }
8447 }
8448
8449 void RSurf_DrawBatch(void)
8450 {
8451         // sometimes a zero triangle surface (usually a degenerate patch) makes it
8452         // through the pipeline, killing it earlier in the pipeline would have
8453         // per-surface overhead rather than per-batch overhead, so it's best to
8454         // reject it here, before it hits glDraw.
8455         if (rsurface.batchnumtriangles == 0)
8456                 return;
8457 #if 0
8458         // batch debugging code
8459         if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8460         {
8461                 int i;
8462                 int j;
8463                 int c;
8464                 const int *e;
8465                 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8466                 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8467                 {
8468                         c = e[i];
8469                         for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8470                         {
8471                                 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8472                                 {
8473                                         if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8474                                                 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);
8475                                         break;
8476                                 }
8477                         }
8478                 }
8479         }
8480 #endif
8481         if (rsurface.batchmultidraw)
8482         {
8483                 // issue multiple draws rather than copying index data
8484                 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8485                 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8486                 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8487                 for (i = 0;i < numsurfaces;)
8488                 {
8489                         // combine consecutive surfaces as one draw
8490                         for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8491                                 if (surfacelist[j] != surfacelist[k] + 1)
8492                                         break;
8493                         firstvertex = surfacelist[i]->num_firstvertex;
8494                         endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8495                         firsttriangle = surfacelist[i]->num_firsttriangle;
8496                         endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8497                         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);
8498                         i = j;
8499                 }
8500         }
8501         else
8502         {
8503                 // there is only one consecutive run of index data (may have been combined)
8504                 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);
8505         }
8506 }
8507
8508 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8509 {
8510         // pick the closest matching water plane
8511         int planeindex, vertexindex, bestplaneindex = -1;
8512         float d, bestd;
8513         vec3_t vert;
8514         const float *v;
8515         r_waterstate_waterplane_t *p;
8516         qboolean prepared = false;
8517         bestd = 0;
8518         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8519         {
8520                 if(p->camera_entity != rsurface.texture->camera_entity)
8521                         continue;
8522                 d = 0;
8523                 if(!prepared)
8524                 {
8525                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8526                         prepared = true;
8527                         if(rsurface.batchnumvertices == 0)
8528                                 break;
8529                 }
8530                 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8531                 {
8532                         Matrix4x4_Transform(&rsurface.matrix, v, vert);
8533                         d += fabs(PlaneDiff(vert, &p->plane));
8534                 }
8535                 if (bestd > d || bestplaneindex < 0)
8536                 {
8537                         bestd = d;
8538                         bestplaneindex = planeindex;
8539                 }
8540         }
8541         return bestplaneindex;
8542         // NOTE: this MAY return a totally unrelated water plane; we can ignore
8543         // this situation though, as it might be better to render single larger
8544         // batches with useless stuff (backface culled for example) than to
8545         // render multiple smaller batches
8546 }
8547
8548 void RSurf_SetupDepthAndCulling(void)
8549 {
8550         // submodels are biased to avoid z-fighting with world surfaces that they
8551         // may be exactly overlapping (avoids z-fighting artifacts on certain
8552         // doors and things in Quake maps)
8553         GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8554         GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8555         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8556         GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8557 }
8558
8559 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8560 {
8561         int i, j;
8562         // transparent sky would be ridiculous
8563         if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8564                 return;
8565         R_SetupShader_Generic_NoTexture(false, false);
8566         skyrenderlater = true;
8567         RSurf_SetupDepthAndCulling();
8568         GL_DepthMask(true);
8569
8570         // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8571         if (r_sky_scissor.integer)
8572         {
8573                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8574                 for (i = 0; i < texturenumsurfaces; i++)
8575                 {
8576                         const msurface_t *surf = texturesurfacelist[i];
8577                         const float *v;
8578                         float p[3];
8579                         float mins[3], maxs[3];
8580                         int scissor[4];
8581                         for (j = 0, v = rsurface.batchvertex3f + 3 * surf->num_firstvertex; j < surf->num_vertices; j++, v += 3)
8582                         {
8583                                 Matrix4x4_Transform(&rsurface.matrix, v, p);
8584                                 if (j > 0)
8585                                 {
8586                                         if (mins[0] > p[0]) mins[0] = p[0];
8587                                         if (mins[1] > p[1]) mins[1] = p[1];
8588                                         if (mins[2] > p[2]) mins[2] = p[2];
8589                                         if (maxs[0] < p[0]) maxs[0] = p[0];
8590                                         if (maxs[1] < p[1]) maxs[1] = p[1];
8591                                         if (maxs[2] < p[2]) maxs[2] = p[2];
8592                                 }
8593                                 else
8594                                 {
8595                                         VectorCopy(p, mins);
8596                                         VectorCopy(p, maxs);
8597                                 }
8598                         }
8599                         if (!R_ScissorForBBox(mins, maxs, scissor))
8600                         {
8601                                 if (skyscissor[2])
8602                                 {
8603                                         if (skyscissor[0] > scissor[0])
8604                                         {
8605                                                 skyscissor[2] += skyscissor[0] - scissor[0];
8606                                                 skyscissor[0] = scissor[0];
8607                                         }
8608                                         if (skyscissor[1] > scissor[1])
8609                                         {
8610                                                 skyscissor[3] += skyscissor[1] - scissor[1];
8611                                                 skyscissor[1] = scissor[1];
8612                                         }
8613                                         if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8614                                                 skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8615                                         if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8616                                                 skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8617                                 }
8618                                 else
8619                                         Vector4Copy(scissor, skyscissor);
8620                         }
8621                 }
8622         }
8623
8624         // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8625         // skymasking on them, and Quake3 never did sky masking (unlike
8626         // software Quake and software Quake2), so disable the sky masking
8627         // in Quake3 maps as it causes problems with q3map2 sky tricks,
8628         // and skymasking also looks very bad when noclipping outside the
8629         // level, so don't use it then either.
8630         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)
8631         {
8632                 R_Mesh_ResetTextureState();
8633                 if (skyrendermasked)
8634                 {
8635                         R_SetupShader_DepthOrShadow(false, false, false);
8636                         // depth-only (masking)
8637                         GL_ColorMask(0, 0, 0, 0);
8638                         // just to make sure that braindead drivers don't draw
8639                         // anything despite that colormask...
8640                         GL_BlendFunc(GL_ZERO, GL_ONE);
8641                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8642                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8643                 }
8644                 else
8645                 {
8646                         R_SetupShader_Generic_NoTexture(false, false);
8647                         // fog sky
8648                         GL_BlendFunc(GL_ONE, GL_ZERO);
8649                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8650                         GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
8651                         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
8652                 }
8653                 RSurf_DrawBatch();
8654                 if (skyrendermasked)
8655                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8656         }
8657         R_Mesh_ResetTextureState();
8658         GL_Color(1, 1, 1, 1);
8659 }
8660
8661 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
8662 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
8663 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass, qboolean ui)
8664 {
8665         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
8666                 return;
8667         if (prepass)
8668         {
8669                 // render screenspace normalmap to texture
8670                 GL_DepthMask(true);
8671                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false);
8672                 RSurf_DrawBatch();
8673                 return;
8674         }
8675
8676         // bind lightmap texture
8677
8678         // water/refraction/reflection/camera surfaces have to be handled specially
8679         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
8680         {
8681                 int start, end, startplaneindex;
8682                 for (start = 0;start < texturenumsurfaces;start = end)
8683                 {
8684                         startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
8685                         if(startplaneindex < 0)
8686                         {
8687                                 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
8688                                 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
8689                                 end = start + 1;
8690                                 continue;
8691                         }
8692                         for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
8693                                 ;
8694                         // now that we have a batch using the same planeindex, render it
8695                         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
8696                         {
8697                                 // render water or distortion background
8698                                 GL_DepthMask(true);
8699                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8700                                 RSurf_DrawBatch();
8701                                 // blend surface on top
8702                                 GL_DepthMask(false);
8703                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false);
8704                                 RSurf_DrawBatch();
8705                         }
8706                         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
8707                         {
8708                                 // render surface with reflection texture as input
8709                                 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8710                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8711                                 RSurf_DrawBatch();
8712                         }
8713                 }
8714                 return;
8715         }
8716
8717         // render surface batch normally
8718         GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8719         R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0 || ui);
8720         RSurf_DrawBatch();
8721 }
8722
8723 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
8724 {
8725         int vi;
8726         int j;
8727         int texturesurfaceindex;
8728         int k;
8729         const msurface_t *surface;
8730         float surfacecolor4f[4];
8731
8732 //      R_Mesh_ResetTextureState();
8733         R_SetupShader_Generic_NoTexture(false, false);
8734
8735         GL_BlendFunc(GL_ONE, GL_ZERO);
8736         GL_DepthMask(writedepth);
8737
8738         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
8739         vi = 0;
8740         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8741         {
8742                 surface = texturesurfacelist[texturesurfaceindex];
8743                 k = (int)(((size_t)surface) / sizeof(msurface_t));
8744                 Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
8745                 for (j = 0;j < surface->num_vertices;j++)
8746                 {
8747                         Vector4Copy(surfacecolor4f, rsurface.batchlightmapcolor4f + 4 * vi);
8748                         vi++;
8749                 }
8750         }
8751         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchlightmapcolor4f, rsurface.batchtexcoordtexture2f);
8752         RSurf_DrawBatch();
8753 }
8754
8755 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass, qboolean ui)
8756 {
8757         CHECKGLERROR
8758         RSurf_SetupDepthAndCulling();
8759         if (r_showsurfaces.integer && r_refdef.view.showdebug)
8760         {
8761                 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
8762                 return;
8763         }
8764         switch (vid.renderpath)
8765         {
8766         case RENDERPATH_GL32:
8767         case RENDERPATH_GLES2:
8768                 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8769                 break;
8770         }
8771         CHECKGLERROR
8772 }
8773
8774 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
8775 {
8776         int i, j;
8777         int texturenumsurfaces, endsurface;
8778         texture_t *texture;
8779         const msurface_t *surface;
8780         const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
8781
8782         RSurf_ActiveModelEntity(ent, true, true, false);
8783
8784         if (r_transparentdepthmasking.integer)
8785         {
8786                 qboolean setup = false;
8787                 for (i = 0;i < numsurfaces;i = j)
8788                 {
8789                         j = i + 1;
8790                         surface = rsurface.modelsurfaces + surfacelist[i];
8791                         texture = surface->texture;
8792                         rsurface.texture = R_GetCurrentTexture(texture);
8793                         rsurface.lightmaptexture = NULL;
8794                         rsurface.deluxemaptexture = NULL;
8795                         rsurface.uselightmaptexture = false;
8796                         // scan ahead until we find a different texture
8797                         endsurface = min(i + 1024, numsurfaces);
8798                         texturenumsurfaces = 0;
8799                         texturesurfacelist[texturenumsurfaces++] = surface;
8800                         for (;j < endsurface;j++)
8801                         {
8802                                 surface = rsurface.modelsurfaces + surfacelist[j];
8803                                 if (texture != surface->texture)
8804                                         break;
8805                                 texturesurfacelist[texturenumsurfaces++] = surface;
8806                         }
8807                         if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
8808                                 continue;
8809                         // render the range of surfaces as depth
8810                         if (!setup)
8811                         {
8812                                 setup = true;
8813                                 GL_ColorMask(0,0,0,0);
8814                                 GL_Color(1,1,1,1);
8815                                 GL_DepthTest(true);
8816                                 GL_BlendFunc(GL_ONE, GL_ZERO);
8817                                 GL_DepthMask(true);
8818 //                              R_Mesh_ResetTextureState();
8819                         }
8820                         RSurf_SetupDepthAndCulling();
8821                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8822                         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8823                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8824                         RSurf_DrawBatch();
8825                 }
8826                 if (setup)
8827                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8828         }
8829
8830         for (i = 0;i < numsurfaces;i = j)
8831         {
8832                 j = i + 1;
8833                 surface = rsurface.modelsurfaces + surfacelist[i];
8834                 texture = surface->texture;
8835                 rsurface.texture = R_GetCurrentTexture(texture);
8836                 // scan ahead until we find a different texture
8837                 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
8838                 texturenumsurfaces = 0;
8839                 texturesurfacelist[texturenumsurfaces++] = surface;
8840                         rsurface.lightmaptexture = surface->lightmaptexture;
8841                         rsurface.deluxemaptexture = surface->deluxemaptexture;
8842                         rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
8843                         for (;j < endsurface;j++)
8844                         {
8845                                 surface = rsurface.modelsurfaces + surfacelist[j];
8846                                 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
8847                                         break;
8848                                 texturesurfacelist[texturenumsurfaces++] = surface;
8849                         }
8850                 // render the range of surfaces
8851                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false, false);
8852         }
8853         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
8854 }
8855
8856 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8857 {
8858         // transparent surfaces get pushed off into the transparent queue
8859         int surfacelistindex;
8860         const msurface_t *surface;
8861         vec3_t tempcenter, center;
8862         for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
8863         {
8864                 surface = texturesurfacelist[surfacelistindex];
8865                 if (r_transparent_sortsurfacesbynearest.integer)
8866                 {
8867                         tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
8868                         tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
8869                         tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
8870                 }
8871                 else
8872                 {
8873                         tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
8874                         tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
8875                         tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
8876                 }
8877                 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
8878                 if (rsurface.entity->transparent_offset) // transparent offset
8879                 {
8880                         center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
8881                         center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
8882                         center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
8883                 }
8884                 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);
8885         }
8886 }
8887
8888 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8889 {
8890         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
8891                 return;
8892         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
8893                 return;
8894         RSurf_SetupDepthAndCulling();
8895         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8896         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8897         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8898         RSurf_DrawBatch();
8899 }
8900
8901 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass, qboolean ui)
8902 {
8903         CHECKGLERROR
8904         if (ui)
8905                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8906         else if (depthonly)
8907                 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
8908         else if (prepass)
8909         {
8910                 if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
8911                         return;
8912                 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8913                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
8914                 else
8915                         R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8916         }
8917         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
8918                 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
8919         else if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
8920                 return;
8921         else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
8922         {
8923                 // in the deferred case, transparent surfaces were queued during prepass
8924                 if (!r_shadow_usingdeferredprepass)
8925                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
8926         }
8927         else
8928         {
8929                 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
8930                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass, ui);
8931         }
8932         CHECKGLERROR
8933 }
8934
8935 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass, qboolean ui)
8936 {
8937         int i, j;
8938         texture_t *texture;
8939         R_FrameData_SetMark();
8940         // break the surface list down into batches by texture and use of lightmapping
8941         for (i = 0;i < numsurfaces;i = j)
8942         {
8943                 j = i + 1;
8944                 // texture is the base texture pointer, rsurface.texture is the
8945                 // current frame/skin the texture is directing us to use (for example
8946                 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
8947                 // use skin 1 instead)
8948                 texture = surfacelist[i]->texture;
8949                 rsurface.texture = R_GetCurrentTexture(texture);
8950                 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
8951                 {
8952                         // if this texture is not the kind we want, skip ahead to the next one
8953                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
8954                                 ;
8955                         continue;
8956                 }
8957                 if(depthonly || prepass)
8958                 {
8959                         rsurface.lightmaptexture = NULL;
8960                         rsurface.deluxemaptexture = NULL;
8961                         rsurface.uselightmaptexture = false;
8962                         // simply scan ahead until we find a different texture or lightmap state
8963                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
8964                                 ;
8965                 }
8966                 else
8967                 {
8968                         rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
8969                         rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
8970                         rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
8971                         // simply scan ahead until we find a different texture or lightmap state
8972                         for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
8973                                 ;
8974                 }
8975                 // render the range of surfaces
8976                 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass, ui);
8977         }
8978         R_FrameData_ReturnToMark();
8979 }
8980
8981 float locboxvertex3f[6*4*3] =
8982 {
8983         1,0,1, 1,0,0, 1,1,0, 1,1,1,
8984         0,1,1, 0,1,0, 0,0,0, 0,0,1,
8985         1,1,1, 1,1,0, 0,1,0, 0,1,1,
8986         0,0,1, 0,0,0, 1,0,0, 1,0,1,
8987         0,0,1, 1,0,1, 1,1,1, 0,1,1,
8988         1,0,0, 0,0,0, 0,1,0, 1,1,0
8989 };
8990
8991 unsigned short locboxelements[6*2*3] =
8992 {
8993          0, 1, 2, 0, 2, 3,
8994          4, 5, 6, 4, 6, 7,
8995          8, 9,10, 8,10,11,
8996         12,13,14, 12,14,15,
8997         16,17,18, 16,18,19,
8998         20,21,22, 20,22,23
8999 };
9000
9001 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9002 {
9003         int i, j;
9004         cl_locnode_t *loc = (cl_locnode_t *)ent;
9005         vec3_t mins, size;
9006         float vertex3f[6*4*3];
9007         CHECKGLERROR
9008         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9009         GL_DepthMask(false);
9010         GL_DepthRange(0, 1);
9011         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9012         GL_DepthTest(true);
9013         GL_CullFace(GL_NONE);
9014         R_EntityMatrix(&identitymatrix);
9015
9016 //      R_Mesh_ResetTextureState();
9017
9018         i = surfacelist[0];
9019         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9020                          ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9021                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9022                         surfacelist[0] < 0 ? 0.5f : 0.125f);
9023
9024         if (VectorCompare(loc->mins, loc->maxs))
9025         {
9026                 VectorSet(size, 2, 2, 2);
9027                 VectorMA(loc->mins, -0.5f, size, mins);
9028         }
9029         else
9030         {
9031                 VectorCopy(loc->mins, mins);
9032                 VectorSubtract(loc->maxs, loc->mins, size);
9033         }
9034
9035         for (i = 0;i < 6*4*3;)
9036                 for (j = 0;j < 3;j++, i++)
9037                         vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9038
9039         R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9040         R_SetupShader_Generic_NoTexture(false, false);
9041         R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9042 }
9043
9044 void R_DrawLocs(void)
9045 {
9046         int index;
9047         cl_locnode_t *loc, *nearestloc;
9048         vec3_t center;
9049         nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9050         for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9051         {
9052                 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9053                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9054         }
9055 }
9056
9057 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9058 {
9059         if (decalsystem->decals)
9060                 Mem_Free(decalsystem->decals);
9061         memset(decalsystem, 0, sizeof(*decalsystem));
9062 }
9063
9064 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)
9065 {
9066         tridecal_t *decal;
9067         tridecal_t *decals;
9068         int i;
9069
9070         // expand or initialize the system
9071         if (decalsystem->maxdecals <= decalsystem->numdecals)
9072         {
9073                 decalsystem_t old = *decalsystem;
9074                 qboolean useshortelements;
9075                 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9076                 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9077                 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)));
9078                 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9079                 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9080                 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9081                 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9082                 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9083                 if (decalsystem->numdecals)
9084                         memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9085                 if (old.decals)
9086                         Mem_Free(old.decals);
9087                 for (i = 0;i < decalsystem->maxdecals*3;i++)
9088                         decalsystem->element3i[i] = i;
9089                 if (useshortelements)
9090                         for (i = 0;i < decalsystem->maxdecals*3;i++)
9091                                 decalsystem->element3s[i] = i;
9092         }
9093
9094         // grab a decal and search for another free slot for the next one
9095         decals = decalsystem->decals;
9096         decal = decalsystem->decals + (i = decalsystem->freedecal++);
9097         for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9098                 ;
9099         decalsystem->freedecal = i;
9100         if (decalsystem->numdecals <= i)
9101                 decalsystem->numdecals = i + 1;
9102
9103         // initialize the decal
9104         decal->lived = 0;
9105         decal->triangleindex = triangleindex;
9106         decal->surfaceindex = surfaceindex;
9107         decal->decalsequence = decalsequence;
9108         decal->color4f[0][0] = c0[0];
9109         decal->color4f[0][1] = c0[1];
9110         decal->color4f[0][2] = c0[2];
9111         decal->color4f[0][3] = 1;
9112         decal->color4f[1][0] = c1[0];
9113         decal->color4f[1][1] = c1[1];
9114         decal->color4f[1][2] = c1[2];
9115         decal->color4f[1][3] = 1;
9116         decal->color4f[2][0] = c2[0];
9117         decal->color4f[2][1] = c2[1];
9118         decal->color4f[2][2] = c2[2];
9119         decal->color4f[2][3] = 1;
9120         decal->vertex3f[0][0] = v0[0];
9121         decal->vertex3f[0][1] = v0[1];
9122         decal->vertex3f[0][2] = v0[2];
9123         decal->vertex3f[1][0] = v1[0];
9124         decal->vertex3f[1][1] = v1[1];
9125         decal->vertex3f[1][2] = v1[2];
9126         decal->vertex3f[2][0] = v2[0];
9127         decal->vertex3f[2][1] = v2[1];
9128         decal->vertex3f[2][2] = v2[2];
9129         decal->texcoord2f[0][0] = t0[0];
9130         decal->texcoord2f[0][1] = t0[1];
9131         decal->texcoord2f[1][0] = t1[0];
9132         decal->texcoord2f[1][1] = t1[1];
9133         decal->texcoord2f[2][0] = t2[0];
9134         decal->texcoord2f[2][1] = t2[1];
9135         TriangleNormal(v0, v1, v2, decal->plane);
9136         VectorNormalize(decal->plane);
9137         decal->plane[3] = DotProduct(v0, decal->plane);
9138 }
9139
9140 extern cvar_t cl_decals_bias;
9141 extern cvar_t cl_decals_models;
9142 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9143 // baseparms, parms, temps
9144 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)
9145 {
9146         int cornerindex;
9147         int index;
9148         float v[9][3];
9149         const float *vertex3f;
9150         const float *normal3f;
9151         int numpoints;
9152         float points[2][9][3];
9153         float temp[3];
9154         float tc[9][2];
9155         float f;
9156         float c[9][4];
9157         const int *e;
9158
9159         e = rsurface.modelelement3i + 3*triangleindex;
9160
9161         vertex3f = rsurface.modelvertex3f;
9162         normal3f = rsurface.modelnormal3f;
9163
9164         if (normal3f)
9165         {
9166                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9167                 {
9168                         index = 3*e[cornerindex];
9169                         VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9170                 }
9171         }
9172         else
9173         {
9174                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9175                 {
9176                         index = 3*e[cornerindex];
9177                         VectorCopy(vertex3f + index, v[cornerindex]);
9178                 }
9179         }
9180
9181         // cull backfaces
9182         //TriangleNormal(v[0], v[1], v[2], normal);
9183         //if (DotProduct(normal, localnormal) < 0.0f)
9184         //      continue;
9185         // clip by each of the box planes formed from the projection matrix
9186         // if anything survives, we emit the decal
9187         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]);
9188         if (numpoints < 3)
9189                 return;
9190         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]);
9191         if (numpoints < 3)
9192                 return;
9193         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]);
9194         if (numpoints < 3)
9195                 return;
9196         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]);
9197         if (numpoints < 3)
9198                 return;
9199         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]);
9200         if (numpoints < 3)
9201                 return;
9202         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]);
9203         if (numpoints < 3)
9204                 return;
9205         // some part of the triangle survived, so we have to accept it...
9206         if (dynamic)
9207         {
9208                 // dynamic always uses the original triangle
9209                 numpoints = 3;
9210                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9211                 {
9212                         index = 3*e[cornerindex];
9213                         VectorCopy(vertex3f + index, v[cornerindex]);
9214                 }
9215         }
9216         for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9217         {
9218                 // convert vertex positions to texcoords
9219                 Matrix4x4_Transform(projection, v[cornerindex], temp);
9220                 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9221                 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9222                 // calculate distance fade from the projection origin
9223                 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9224                 f = bound(0.0f, f, 1.0f);
9225                 c[cornerindex][0] = r * f;
9226                 c[cornerindex][1] = g * f;
9227                 c[cornerindex][2] = b * f;
9228                 c[cornerindex][3] = 1.0f;
9229                 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9230         }
9231         if (dynamic)
9232                 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);
9233         else
9234                 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9235                         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);
9236 }
9237 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)
9238 {
9239         matrix4x4_t projection;
9240         decalsystem_t *decalsystem;
9241         qboolean dynamic;
9242         dp_model_t *model;
9243         const msurface_t *surface;
9244         const msurface_t *surfaces;
9245         const int *surfacelist;
9246         const texture_t *texture;
9247         int numtriangles;
9248         int numsurfacelist;
9249         int surfacelistindex;
9250         int surfaceindex;
9251         int triangleindex;
9252         float localorigin[3];
9253         float localnormal[3];
9254         float localmins[3];
9255         float localmaxs[3];
9256         float localsize;
9257         //float normal[3];
9258         float planes[6][4];
9259         float angles[3];
9260         bih_t *bih;
9261         int bih_triangles_count;
9262         int bih_triangles[256];
9263         int bih_surfaces[256];
9264
9265         decalsystem = &ent->decalsystem;
9266         model = ent->model;
9267         if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9268         {
9269                 R_DecalSystem_Reset(&ent->decalsystem);
9270                 return;
9271         }
9272
9273         if (!model->brush.data_leafs && !cl_decals_models.integer)
9274         {
9275                 if (decalsystem->model)
9276                         R_DecalSystem_Reset(decalsystem);
9277                 return;
9278         }
9279
9280         if (decalsystem->model != model)
9281                 R_DecalSystem_Reset(decalsystem);
9282         decalsystem->model = model;
9283
9284         RSurf_ActiveModelEntity(ent, true, false, false);
9285
9286         Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9287         Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9288         VectorNormalize(localnormal);
9289         localsize = worldsize*rsurface.inversematrixscale;
9290         localmins[0] = localorigin[0] - localsize;
9291         localmins[1] = localorigin[1] - localsize;
9292         localmins[2] = localorigin[2] - localsize;
9293         localmaxs[0] = localorigin[0] + localsize;
9294         localmaxs[1] = localorigin[1] + localsize;
9295         localmaxs[2] = localorigin[2] + localsize;
9296
9297         //VectorCopy(localnormal, planes[4]);
9298         //VectorVectors(planes[4], planes[2], planes[0]);
9299         AnglesFromVectors(angles, localnormal, NULL, false);
9300         AngleVectors(angles, planes[0], planes[2], planes[4]);
9301         VectorNegate(planes[0], planes[1]);
9302         VectorNegate(planes[2], planes[3]);
9303         VectorNegate(planes[4], planes[5]);
9304         planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9305         planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9306         planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9307         planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9308         planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9309         planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9310
9311 #if 1
9312 // works
9313 {
9314         matrix4x4_t forwardprojection;
9315         Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9316         Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9317 }
9318 #else
9319 // broken
9320 {
9321         float projectionvector[4][3];
9322         VectorScale(planes[0], ilocalsize, projectionvector[0]);
9323         VectorScale(planes[2], ilocalsize, projectionvector[1]);
9324         VectorScale(planes[4], ilocalsize, projectionvector[2]);
9325         projectionvector[0][0] = planes[0][0] * ilocalsize;
9326         projectionvector[0][1] = planes[1][0] * ilocalsize;
9327         projectionvector[0][2] = planes[2][0] * ilocalsize;
9328         projectionvector[1][0] = planes[0][1] * ilocalsize;
9329         projectionvector[1][1] = planes[1][1] * ilocalsize;
9330         projectionvector[1][2] = planes[2][1] * ilocalsize;
9331         projectionvector[2][0] = planes[0][2] * ilocalsize;
9332         projectionvector[2][1] = planes[1][2] * ilocalsize;
9333         projectionvector[2][2] = planes[2][2] * ilocalsize;
9334         projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9335         projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9336         projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9337         Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9338 }
9339 #endif
9340
9341         dynamic = model->surfmesh.isanimated;
9342         numsurfacelist = model->nummodelsurfaces;
9343         surfacelist = model->sortedmodelsurfaces;
9344         surfaces = model->data_surfaces;
9345
9346         bih = NULL;
9347         bih_triangles_count = -1;
9348         if(!dynamic)
9349         {
9350                 if(model->render_bih.numleafs)
9351                         bih = &model->render_bih;
9352                 else if(model->collision_bih.numleafs)
9353                         bih = &model->collision_bih;
9354         }
9355         if(bih)
9356                 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9357         if(bih_triangles_count == 0)
9358                 return;
9359         if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9360                 return;
9361         if(bih_triangles_count > 0)
9362         {
9363                 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9364                 {
9365                         surfaceindex = bih_surfaces[triangleindex];
9366                         surface = surfaces + surfaceindex;
9367                         texture = surface->texture;
9368                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9369                                 continue;
9370                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9371                                 continue;
9372                         R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9373                 }
9374         }
9375         else
9376         {
9377                 for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
9378                 {
9379                         surfaceindex = surfacelist[surfacelistindex];
9380                         surface = surfaces + surfaceindex;
9381                         // check cull box first because it rejects more than any other check
9382                         if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9383                                 continue;
9384                         // skip transparent surfaces
9385                         texture = surface->texture;
9386                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9387                                 continue;
9388                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9389                                 continue;
9390                         numtriangles = surface->num_triangles;
9391                         for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9392                                 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9393                 }
9394         }
9395 }
9396
9397 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9398 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)
9399 {
9400         int renderentityindex;
9401         float worldmins[3];
9402         float worldmaxs[3];
9403         entity_render_t *ent;
9404
9405         worldmins[0] = worldorigin[0] - worldsize;
9406         worldmins[1] = worldorigin[1] - worldsize;
9407         worldmins[2] = worldorigin[2] - worldsize;
9408         worldmaxs[0] = worldorigin[0] + worldsize;
9409         worldmaxs[1] = worldorigin[1] + worldsize;
9410         worldmaxs[2] = worldorigin[2] + worldsize;
9411
9412         R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9413
9414         for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9415         {
9416                 ent = r_refdef.scene.entities[renderentityindex];
9417                 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9418                         continue;
9419
9420                 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9421         }
9422 }
9423
9424 typedef struct r_decalsystem_splatqueue_s
9425 {
9426         vec3_t worldorigin;
9427         vec3_t worldnormal;
9428         float color[4];
9429         float tcrange[4];
9430         float worldsize;
9431         unsigned int decalsequence;
9432 }
9433 r_decalsystem_splatqueue_t;
9434
9435 int r_decalsystem_numqueued = 0;
9436 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9437
9438 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)
9439 {
9440         r_decalsystem_splatqueue_t *queue;
9441
9442         if (r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9443                 return;
9444
9445         queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9446         VectorCopy(worldorigin, queue->worldorigin);
9447         VectorCopy(worldnormal, queue->worldnormal);
9448         Vector4Set(queue->color, r, g, b, a);
9449         Vector4Set(queue->tcrange, s1, t1, s2, t2);
9450         queue->worldsize = worldsize;
9451         queue->decalsequence = cl.decalsequence++;
9452 }
9453
9454 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9455 {
9456         int i;
9457         r_decalsystem_splatqueue_t *queue;
9458
9459         for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9460                 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);
9461         r_decalsystem_numqueued = 0;
9462 }
9463
9464 extern cvar_t cl_decals_max;
9465 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9466 {
9467         int i;
9468         decalsystem_t *decalsystem = &ent->decalsystem;
9469         int numdecals;
9470         unsigned int killsequence;
9471         tridecal_t *decal;
9472         float frametime;
9473         float lifetime;
9474
9475         if (!decalsystem->numdecals)
9476                 return;
9477
9478         if (r_showsurfaces.integer)
9479                 return;
9480
9481         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9482         {
9483                 R_DecalSystem_Reset(decalsystem);
9484                 return;
9485         }
9486
9487         killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9488         lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9489
9490         if (decalsystem->lastupdatetime)
9491                 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9492         else
9493                 frametime = 0;
9494         decalsystem->lastupdatetime = r_refdef.scene.time;
9495         numdecals = decalsystem->numdecals;
9496
9497         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9498         {
9499                 if (decal->color4f[0][3])
9500                 {
9501                         decal->lived += frametime;
9502                         if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9503                         {
9504                                 memset(decal, 0, sizeof(*decal));
9505                                 if (decalsystem->freedecal > i)
9506                                         decalsystem->freedecal = i;
9507                         }
9508                 }
9509         }
9510         decal = decalsystem->decals;
9511         while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9512                 numdecals--;
9513
9514         // collapse the array by shuffling the tail decals into the gaps
9515         for (;;)
9516         {
9517                 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
9518                         decalsystem->freedecal++;
9519                 if (decalsystem->freedecal == numdecals)
9520                         break;
9521                 decal[decalsystem->freedecal] = decal[--numdecals];
9522         }
9523
9524         decalsystem->numdecals = numdecals;
9525
9526         if (numdecals <= 0)
9527         {
9528                 // if there are no decals left, reset decalsystem
9529                 R_DecalSystem_Reset(decalsystem);
9530         }
9531 }
9532
9533 extern skinframe_t *decalskinframe;
9534 static void R_DrawModelDecals_Entity(entity_render_t *ent)
9535 {
9536         int i;
9537         decalsystem_t *decalsystem = &ent->decalsystem;
9538         int numdecals;
9539         tridecal_t *decal;
9540         float faderate;
9541         float alpha;
9542         float *v3f;
9543         float *c4f;
9544         float *t2f;
9545         const int *e;
9546         const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
9547         int numtris = 0;
9548
9549         numdecals = decalsystem->numdecals;
9550         if (!numdecals)
9551                 return;
9552
9553         if (r_showsurfaces.integer)
9554                 return;
9555
9556         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9557         {
9558                 R_DecalSystem_Reset(decalsystem);
9559                 return;
9560         }
9561
9562         // if the model is static it doesn't matter what value we give for
9563         // wantnormals and wanttangents, so this logic uses only rules applicable
9564         // to a model, knowing that they are meaningless otherwise
9565         RSurf_ActiveModelEntity(ent, false, false, false);
9566
9567         decalsystem->lastupdatetime = r_refdef.scene.time;
9568
9569         faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
9570
9571         // update vertex positions for animated models
9572         v3f = decalsystem->vertex3f;
9573         c4f = decalsystem->color4f;
9574         t2f = decalsystem->texcoord2f;
9575         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9576         {
9577                 if (!decal->color4f[0][3])
9578                         continue;
9579
9580                 if (surfacevisible && !surfacevisible[decal->surfaceindex])
9581                         continue;
9582
9583                 // skip backfaces
9584                 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
9585                         continue;
9586
9587                 // update color values for fading decals
9588                 if (decal->lived >= cl_decals_time.value)
9589                         alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
9590                 else
9591                         alpha = 1.0f;
9592
9593                 c4f[ 0] = decal->color4f[0][0] * alpha;
9594                 c4f[ 1] = decal->color4f[0][1] * alpha;
9595                 c4f[ 2] = decal->color4f[0][2] * alpha;
9596                 c4f[ 3] = 1;
9597                 c4f[ 4] = decal->color4f[1][0] * alpha;
9598                 c4f[ 5] = decal->color4f[1][1] * alpha;
9599                 c4f[ 6] = decal->color4f[1][2] * alpha;
9600                 c4f[ 7] = 1;
9601                 c4f[ 8] = decal->color4f[2][0] * alpha;
9602                 c4f[ 9] = decal->color4f[2][1] * alpha;
9603                 c4f[10] = decal->color4f[2][2] * alpha;
9604                 c4f[11] = 1;
9605
9606                 t2f[0] = decal->texcoord2f[0][0];
9607                 t2f[1] = decal->texcoord2f[0][1];
9608                 t2f[2] = decal->texcoord2f[1][0];
9609                 t2f[3] = decal->texcoord2f[1][1];
9610                 t2f[4] = decal->texcoord2f[2][0];
9611                 t2f[5] = decal->texcoord2f[2][1];
9612
9613                 // update vertex positions for animated models
9614                 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
9615                 {
9616                         e = rsurface.modelelement3i + 3*decal->triangleindex;
9617                         VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
9618                         VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
9619                         VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
9620                 }
9621                 else
9622                 {
9623                         VectorCopy(decal->vertex3f[0], v3f);
9624                         VectorCopy(decal->vertex3f[1], v3f + 3);
9625                         VectorCopy(decal->vertex3f[2], v3f + 6);
9626                 }
9627
9628                 if (r_refdef.fogenabled)
9629                 {
9630                         alpha = RSurf_FogVertex(v3f);
9631                         VectorScale(c4f, alpha, c4f);
9632                         alpha = RSurf_FogVertex(v3f + 3);
9633                         VectorScale(c4f + 4, alpha, c4f + 4);
9634                         alpha = RSurf_FogVertex(v3f + 6);
9635                         VectorScale(c4f + 8, alpha, c4f + 8);
9636                 }
9637
9638                 v3f += 9;
9639                 c4f += 12;
9640                 t2f += 6;
9641                 numtris++;
9642         }
9643
9644         if (numtris > 0)
9645         {
9646                 r_refdef.stats[r_stat_drawndecals] += numtris;
9647
9648                 // now render the decals all at once
9649                 // (this assumes they all use one particle font texture!)
9650                 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);
9651 //              R_Mesh_ResetTextureState();
9652                 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
9653                 GL_DepthMask(false);
9654                 GL_DepthRange(0, 1);
9655                 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
9656                 GL_DepthTest(true);
9657                 GL_CullFace(GL_NONE);
9658                 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
9659                 R_SetupShader_Generic(decalskinframe->base, false, false, false);
9660                 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
9661         }
9662 }
9663
9664 static void R_DrawModelDecals(void)
9665 {
9666         int i, numdecals;
9667
9668         // fade faster when there are too many decals
9669         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9670         for (i = 0;i < r_refdef.scene.numentities;i++)
9671                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9672
9673         R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
9674         for (i = 0;i < r_refdef.scene.numentities;i++)
9675                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9676                         R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
9677
9678         R_DecalSystem_ApplySplatEntitiesQueue();
9679
9680         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9681         for (i = 0;i < r_refdef.scene.numentities;i++)
9682                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9683
9684         r_refdef.stats[r_stat_totaldecals] += numdecals;
9685
9686         if (r_showsurfaces.integer || !r_drawdecals.integer)
9687                 return;
9688
9689         R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
9690
9691         for (i = 0;i < r_refdef.scene.numentities;i++)
9692         {
9693                 if (!r_refdef.viewcache.entityvisible[i])
9694                         continue;
9695                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9696                         R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
9697         }
9698 }
9699
9700 extern cvar_t mod_collision_bih;
9701 static void R_DrawDebugModel(void)
9702 {
9703         entity_render_t *ent = rsurface.entity;
9704         int i, j, flagsmask;
9705         const msurface_t *surface;
9706         dp_model_t *model = ent->model;
9707
9708         if (!sv.active  && !cls.demoplayback && ent != r_refdef.scene.worldentity)
9709                 return;
9710
9711         if (r_showoverdraw.value > 0)
9712         {
9713                 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
9714                 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9715                 R_SetupShader_Generic_NoTexture(false, false);
9716                 GL_DepthTest(false);
9717                 GL_DepthMask(false);
9718                 GL_DepthRange(0, 1);
9719                 GL_BlendFunc(GL_ONE, GL_ONE);
9720                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9721                 {
9722                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9723                                 continue;
9724                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9725                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9726                         {
9727                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
9728                                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
9729                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9730                                         GL_Color(c, 0, 0, 1.0f);
9731                                 else if (ent == r_refdef.scene.worldentity)
9732                                         GL_Color(c, c, c, 1.0f);
9733                                 else
9734                                         GL_Color(0, c, 0, 1.0f);
9735                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9736                                 RSurf_DrawBatch();
9737                         }
9738                 }
9739                 rsurface.texture = NULL;
9740         }
9741
9742         flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9743
9744 //      R_Mesh_ResetTextureState();
9745         R_SetupShader_Generic_NoTexture(false, false);
9746         GL_DepthRange(0, 1);
9747         GL_DepthTest(!r_showdisabledepthtest.integer);
9748         GL_DepthMask(false);
9749         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9750
9751         if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
9752         {
9753                 int triangleindex;
9754                 int bihleafindex;
9755                 qboolean cullbox = false;
9756                 const q3mbrush_t *brush;
9757                 const bih_t *bih = &model->collision_bih;
9758                 const bih_leaf_t *bihleaf;
9759                 float vertex3f[3][3];
9760                 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
9761                 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
9762                 {
9763                         if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
9764                                 continue;
9765                         switch (bihleaf->type)
9766                         {
9767                         case BIH_BRUSH:
9768                                 brush = model->brush.data_brushes + bihleaf->itemindex;
9769                                 if (brush->colbrushf && brush->colbrushf->numtriangles)
9770                                 {
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(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
9773                                         R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
9774                                 }
9775                                 break;
9776                         case BIH_COLLISIONTRIANGLE:
9777                                 triangleindex = bihleaf->itemindex;
9778                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
9779                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
9780                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
9781                                 GL_Color((bihleafindex & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value);
9782                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9783                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9784                                 break;
9785                         case BIH_RENDERTRIANGLE:
9786                                 triangleindex = bihleaf->itemindex;
9787                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
9788                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
9789                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
9790                                 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);
9791                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9792                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9793                                 break;
9794                         }
9795                 }
9796         }
9797
9798         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9799
9800 #ifndef USE_GLES2
9801         if (r_showtris.value > 0 && qglPolygonMode)
9802         {
9803                 if (r_showdisabledepthtest.integer)
9804                 {
9805                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9806                         GL_DepthMask(false);
9807                 }
9808                 else
9809                 {
9810                         GL_BlendFunc(GL_ONE, GL_ZERO);
9811                         GL_DepthMask(true);
9812                 }
9813                 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
9814                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9815                 {
9816                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9817                                 continue;
9818                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9819                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9820                         {
9821                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9822                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9823                                         GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
9824                                 else if (ent == r_refdef.scene.worldentity)
9825                                         GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
9826                                 else
9827                                         GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
9828                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9829                                 RSurf_DrawBatch();
9830                         }
9831                 }
9832                 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
9833                 rsurface.texture = NULL;
9834         }
9835
9836 # if 0
9837         // FIXME!  implement r_shownormals with just triangles
9838         if (r_shownormals.value != 0 && qglBegin)
9839         {
9840                 int l, k;
9841                 vec3_t v;
9842                 if (r_showdisabledepthtest.integer)
9843                 {
9844                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9845                         GL_DepthMask(false);
9846                 }
9847                 else
9848                 {
9849                         GL_BlendFunc(GL_ONE, GL_ZERO);
9850                         GL_DepthMask(true);
9851                 }
9852                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9853                 {
9854                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9855                                 continue;
9856                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9857                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9858                         {
9859                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9860                                 qglBegin(GL_LINES);
9861                                 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
9862                                 {
9863                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9864                                         {
9865                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9866                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9867                                                 qglVertex3f(v[0], v[1], v[2]);
9868                                                 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9869                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9870                                                 qglVertex3f(v[0], v[1], v[2]);
9871                                         }
9872                                 }
9873                                 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
9874                                 {
9875                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9876                                         {
9877                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9878                                                 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
9879                                                 qglVertex3f(v[0], v[1], v[2]);
9880                                                 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
9881                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9882                                                 qglVertex3f(v[0], v[1], v[2]);
9883                                         }
9884                                 }
9885                                 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
9886                                 {
9887                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9888                                         {
9889                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9890                                                 GL_Color(0, r_refdef.view.colorscale, 0, 1);
9891                                                 qglVertex3f(v[0], v[1], v[2]);
9892                                                 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
9893                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9894                                                 qglVertex3f(v[0], v[1], v[2]);
9895                                         }
9896                                 }
9897                                 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
9898                                 {
9899                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9900                                         {
9901                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9902                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9903                                                 qglVertex3f(v[0], v[1], v[2]);
9904                                                 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9905                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9906                                                 qglVertex3f(v[0], v[1], v[2]);
9907                                         }
9908                                 }
9909                                 qglEnd();
9910                                 CHECKGLERROR
9911                         }
9912                 }
9913                 rsurface.texture = NULL;
9914         }
9915 # endif
9916 #endif
9917 }
9918
9919 int r_maxsurfacelist = 0;
9920 const msurface_t **r_surfacelist = NULL;
9921 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass, qboolean ui)
9922 {
9923         int i, j, endj, flagsmask;
9924         dp_model_t *model = ent->model;
9925         msurface_t *surfaces;
9926         unsigned char *update;
9927         int numsurfacelist = 0;
9928         if (model == NULL)
9929                 return;
9930
9931         if (r_maxsurfacelist < model->num_surfaces)
9932         {
9933                 r_maxsurfacelist = model->num_surfaces;
9934                 if (r_surfacelist)
9935                         Mem_Free((msurface_t **)r_surfacelist);
9936                 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
9937         }
9938
9939         if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
9940                 RSurf_ActiveModelEntity(ent, false, false, false);
9941         else if (prepass)
9942                 RSurf_ActiveModelEntity(ent, true, true, true);
9943         else if (depthonly)
9944                 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
9945         else
9946                 RSurf_ActiveModelEntity(ent, true, true, false);
9947
9948         surfaces = model->data_surfaces;
9949         update = model->brushq1.lightmapupdateflags;
9950
9951         // update light styles
9952         if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0)
9953         {
9954                 model_brush_lightstyleinfo_t *style;
9955                 for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
9956                 {
9957                         if (style->value != r_refdef.scene.lightstylevalue[style->style])
9958                         {
9959                                 int *list = style->surfacelist;
9960                                 style->value = r_refdef.scene.lightstylevalue[style->style];
9961                                 for (j = 0;j < style->numsurfaces;j++)
9962                                         update[list[j]] = true;
9963                         }
9964                 }
9965         }
9966
9967         flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
9968
9969         if (debug)
9970         {
9971                 R_DrawDebugModel();
9972                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
9973                 return;
9974         }
9975
9976         rsurface.lightmaptexture = NULL;
9977         rsurface.deluxemaptexture = NULL;
9978         rsurface.uselightmaptexture = false;
9979         rsurface.texture = NULL;
9980         rsurface.rtlight = NULL;
9981         numsurfacelist = 0;
9982         // add visible surfaces to draw list
9983         if (ent == r_refdef.scene.worldentity)
9984         {
9985                 // for the world entity, check surfacevisible
9986                 for (i = 0;i < model->nummodelsurfaces;i++)
9987                 {
9988                         j = model->sortedmodelsurfaces[i];
9989                         if (r_refdef.viewcache.world_surfacevisible[j])
9990                                 r_surfacelist[numsurfacelist++] = surfaces + j;
9991                 }
9992         }
9993         else if (ui)
9994         {
9995                 // for ui we have to preserve the order of surfaces
9996                 for (i = 0; i < model->nummodelsurfaces; i++)
9997                         r_surfacelist[numsurfacelist++] = surfaces + model->firstmodelsurface + i;
9998         }
9999         else
10000         {
10001                 // add all surfaces
10002                 for (i = 0; i < model->nummodelsurfaces; i++)
10003                         r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
10004         }
10005         // don't do anything if there were no surfaces
10006         if (!numsurfacelist)
10007         {
10008                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10009                 return;
10010         }
10011         // update lightmaps if needed
10012         if (update)
10013         {
10014                 int updated = 0;
10015                 for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
10016                 {
10017                         if (update[j])
10018                         {
10019                                 updated++;
10020                                 R_BuildLightMap(ent, surfaces + j);
10021                         }
10022                 }
10023         }
10024
10025         R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass, ui);
10026
10027         // add to stats if desired
10028         if (r_speeds.integer && !skysurfaces && !depthonly)
10029         {
10030                 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10031                 for (j = 0;j < numsurfacelist;j++)
10032                         r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10033         }
10034
10035         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10036 }
10037
10038 void R_DebugLine(vec3_t start, vec3_t end)
10039 {
10040         dp_model_t *mod = CL_Mesh_UI();
10041         msurface_t *surf;
10042         int e0, e1, e2, e3;
10043         float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10044         float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10045         float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10046         vec4_t w[2], s[2];
10047
10048         // transform to screen coords first
10049         Vector4Set(w[0], start[0], start[1], start[2], 1);
10050         Vector4Set(w[1], end[0], end[1], end[2], 1);
10051         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10052         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10053         x1 = s[0][0] * vid_conwidth.value / vid.width;
10054         y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10055         x2 = s[1][0] * vid_conwidth.value / vid.width;
10056         y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10057         //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10058
10059         // add the line to the UI mesh for drawing later
10060
10061         // width is measured in real pixels
10062         if (fabs(x2 - x1) > fabs(y2 - y1))
10063         {
10064                 offsetx = 0;
10065                 offsety = 0.5f * width * vid_conheight.value / vid.height;
10066         }
10067         else
10068         {
10069                 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10070                 offsety = 0;
10071         }
10072         surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_WALL | MATERIALFLAG_VERTEXCOLOR | MATERIALFLAG_ALPHAGEN_VERTEX), true);
10073         e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10074         e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10075         e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10076         e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10077         Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10078         Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10079
10080 }
10081
10082
10083 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)
10084 {
10085         static texture_t texture;
10086
10087         // fake enough texture and surface state to render this geometry
10088
10089         texture.update_lastrenderframe = -1; // regenerate this texture
10090         texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10091         texture.basealpha = 1.0f;
10092         texture.currentskinframe = skinframe;
10093         texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10094         texture.offsetmapping = OFFSETMAPPING_OFF;
10095         texture.offsetscale = 1;
10096         texture.specularscalemod = 1;
10097         texture.specularpowermod = 1;
10098         texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10099
10100         R_DrawCustomSurface_Texture(&texture, texmatrix, materialflags, firstvertex, numvertices, firsttriangle, numtriangles, writedepth, prepass, ui);
10101 }
10102
10103 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)
10104 {
10105         static msurface_t surface;
10106         const msurface_t *surfacelist = &surface;
10107
10108         // fake enough texture and surface state to render this geometry
10109         surface.texture = texture;
10110         surface.num_triangles = numtriangles;
10111         surface.num_firsttriangle = firsttriangle;
10112         surface.num_vertices = numvertices;
10113         surface.num_firstvertex = firstvertex;
10114
10115         // now render it
10116         rsurface.texture = R_GetCurrentTexture(surface.texture);
10117         rsurface.lightmaptexture = NULL;
10118         rsurface.deluxemaptexture = NULL;
10119         rsurface.uselightmaptexture = false;
10120         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass, ui);
10121 }