]> git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
Fix most Q3 & QL glow maps
[xonotic/darkplaces.git] / gl_rmain.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_main.c
21
22 #include "quakedef.h"
23 #include "r_shadow.h"
24 #include "polygon.h"
25 #include "image.h"
26 #include "ft2.h"
27 #include "csprogs.h"
28 #include "cl_video.h"
29 #include "cl_collision.h"
30
31 #ifdef WIN32
32 // Enable NVIDIA High Performance Graphics while using Integrated Graphics.
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36 __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
37 #ifdef __cplusplus
38 }
39 #endif
40 #endif
41
42 mempool_t *r_main_mempool;
43 rtexturepool_t *r_main_texturepool;
44
45 int r_textureframe = 0; ///< used only by R_GetCurrentTexture, incremented per view and per UI render
46
47 static qboolean r_loadnormalmap;
48 static qboolean r_loadgloss;
49 qboolean r_loadfog;
50 static qboolean r_loaddds;
51 static qboolean r_savedds;
52 static qboolean r_gpuskeletal;
53
54 //
55 // screen size info
56 //
57 r_refdef_t r_refdef;
58
59 cvar_t r_motionblur = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur", "0", "screen motionblur - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
60 cvar_t r_damageblur = {CVAR_CLIENT | CVAR_SAVE, "r_damageblur", "0", "screen motionblur based on damage - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
61 cvar_t r_motionblur_averaging = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_averaging", "0.1", "sliding average reaction time for velocity (higher = slower adaption to change)"};
62 cvar_t r_motionblur_randomize = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"};
63 cvar_t r_motionblur_minblur = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_minblur", "0.5", "factor of blur to apply at all times (always have this amount of blur no matter what the other factors are)"};
64 cvar_t r_motionblur_maxblur = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_maxblur", "0.9", "maxmimum amount of blur"};
65 cvar_t r_motionblur_velocityfactor = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_velocityfactor", "1", "factoring in of player velocity to the blur equation - the faster the player moves around the map, the more blur they get"};
66 cvar_t r_motionblur_velocityfactor_minspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_velocityfactor_minspeed", "400", "lower value of velocity when it starts to factor into blur equation"};
67 cvar_t r_motionblur_velocityfactor_maxspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_velocityfactor_maxspeed", "800", "upper value of velocity when it reaches the peak factor into blur equation"};
68 cvar_t r_motionblur_mousefactor = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_mousefactor", "2", "factoring in of mouse acceleration to the blur equation - the faster the player turns their mouse, the more blur they get"};
69 cvar_t r_motionblur_mousefactor_minspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_mousefactor_minspeed", "0", "lower value of mouse acceleration when it starts to factor into blur equation"};
70 cvar_t r_motionblur_mousefactor_maxspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_mousefactor_maxspeed", "50", "upper value of mouse acceleration when it reaches the peak factor into blur equation"};
71
72 cvar_t r_depthfirst = {CVAR_CLIENT | CVAR_SAVE, "r_depthfirst", "0", "renders a depth-only version of the scene before normal rendering begins to eliminate overdraw, values: 0 = off, 1 = world depth, 2 = world and model depth"};
73 cvar_t r_useinfinitefarclip = {CVAR_CLIENT | CVAR_SAVE, "r_useinfinitefarclip", "1", "enables use of a special kind of projection matrix that has an extremely large farclip"};
74 cvar_t r_farclip_base = {CVAR_CLIENT, "r_farclip_base", "65536", "farclip (furthest visible distance) for rendering when r_useinfinitefarclip is 0"};
75 cvar_t r_farclip_world = {CVAR_CLIENT, "r_farclip_world", "2", "adds map size to farclip multiplied by this value"};
76 cvar_t r_nearclip = {CVAR_CLIENT, "r_nearclip", "1", "distance from camera of nearclip plane" };
77 cvar_t r_deformvertexes = {CVAR_CLIENT, "r_deformvertexes", "1", "allows use of deformvertexes in shader files (can be turned off to check performance impact)"};
78 cvar_t r_transparent = {CVAR_CLIENT, "r_transparent", "1", "allows use of transparent surfaces (can be turned off to check performance impact)"};
79 cvar_t r_transparent_alphatocoverage = {CVAR_CLIENT, "r_transparent_alphatocoverage", "1", "enables GL_ALPHA_TO_COVERAGE antialiasing technique on alphablend and alphatest surfaces when using vid_samples 2 or higher"};
80 cvar_t r_transparent_sortsurfacesbynearest = {CVAR_CLIENT, "r_transparent_sortsurfacesbynearest", "1", "sort entity and world surfaces by nearest point on bounding box instead of using the center of the bounding box, usually reduces sorting artifacts"};
81 cvar_t r_transparent_useplanardistance = {CVAR_CLIENT, "r_transparent_useplanardistance", "0", "sort transparent meshes by distance from view plane rather than spherical distance to the chosen point"};
82 cvar_t r_showoverdraw = {CVAR_CLIENT, "r_showoverdraw", "0", "shows overlapping geometry"};
83 cvar_t r_showbboxes = {CVAR_CLIENT, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
84 cvar_t r_showbboxes_client = {CVAR_CLIENT, "r_showbboxes_client", "0", "shows bounding boxes of clientside qc entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
85 cvar_t r_showsurfaces = {CVAR_CLIENT, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 2 shows triangle draw order (for analyzing whether meshes are optimized for vertex cache)"};
86 cvar_t r_showtris = {CVAR_CLIENT, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
87 cvar_t r_shownormals = {CVAR_CLIENT, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
88 cvar_t r_showlighting = {CVAR_CLIENT, "r_showlighting", "0", "shows areas lit by lights, useful for finding out why some areas of a map render slowly (bright orange = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
89 cvar_t r_showcollisionbrushes = {CVAR_CLIENT, "r_showcollisionbrushes", "0", "draws collision brushes in quake3 maps (mode 1), mode 2 disables rendering of world (trippy!)"};
90 cvar_t r_showcollisionbrushes_polygonfactor = {CVAR_CLIENT, "r_showcollisionbrushes_polygonfactor", "-1", "expands outward the brush polygons a little bit, used to make collision brushes appear infront of walls"};
91 cvar_t r_showcollisionbrushes_polygonoffset = {CVAR_CLIENT, "r_showcollisionbrushes_polygonoffset", "0", "nudges brush polygon depth in hardware depth units, used to make collision brushes appear infront of walls"};
92 cvar_t r_showdisabledepthtest = {CVAR_CLIENT, "r_showdisabledepthtest", "0", "disables depth testing on r_show* cvars, allowing you to see what hidden geometry the graphics card is processing"};
93 cvar_t r_showspriteedges = {CVAR_CLIENT, "r_showspriteedges", "0", "renders a debug outline to show the polygon shape of each sprite frame rendered (may be 2 or more in case of interpolated animations), for debugging rendering bugs with specific view types"};
94 cvar_t r_showparticleedges = {CVAR_CLIENT, "r_showparticleedges", "0", "renders a debug outline to show the polygon shape of each particle, for debugging rendering bugs with specific view types"};
95 cvar_t r_drawportals = {CVAR_CLIENT, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
96 cvar_t r_drawentities = {CVAR_CLIENT, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
97 cvar_t r_draw2d = {CVAR_CLIENT, "r_draw2d","1", "draw 2D stuff (dangerous to turn off)"};
98 cvar_t r_drawworld = {CVAR_CLIENT, "r_drawworld","1", "draw world (most static stuff)"};
99 cvar_t r_drawviewmodel = {CVAR_CLIENT, "r_drawviewmodel","1", "draw your weapon model"};
100 cvar_t r_drawexteriormodel = {CVAR_CLIENT, "r_drawexteriormodel","1", "draw your player model (e.g. in chase cam, reflections)"};
101 cvar_t r_cullentities_trace = {CVAR_CLIENT, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
102 cvar_t r_cullentities_trace_entityocclusion = {CVAR_CLIENT, "r_cullentities_trace_entityocclusion", "1", "check for occluding entities such as doors, not just world hull"};
103 cvar_t r_cullentities_trace_samples = {CVAR_CLIENT, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling (in addition to center sample)"};
104 cvar_t r_cullentities_trace_tempentitysamples = {CVAR_CLIENT, "r_cullentities_trace_tempentitysamples", "-1", "number of samples to test for entity culling of temp entities (including all CSQC entities), -1 disables trace culling on these entities to prevent flicker (pvs still applies)"};
105 cvar_t r_cullentities_trace_enlarge = {CVAR_CLIENT, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
106 cvar_t r_cullentities_trace_expand = {CVAR_CLIENT, "r_cullentities_trace_expand", "0", "box expanded by this many units for entity culling"};
107 cvar_t r_cullentities_trace_pad = {CVAR_CLIENT, "r_cullentities_trace_pad", "8", "accept traces that hit within this many units of the box"};
108 cvar_t r_cullentities_trace_delay = {CVAR_CLIENT, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
109 cvar_t r_cullentities_trace_eyejitter = {CVAR_CLIENT, "r_cullentities_trace_eyejitter", "16", "randomly offset rays from the eye by this much to reduce the odds of flickering"};
110 cvar_t r_sortentities = {CVAR_CLIENT, "r_sortentities", "0", "sort entities before drawing (might be faster)"};
111 cvar_t r_speeds = {CVAR_CLIENT, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
112 cvar_t r_fullbright = {CVAR_CLIENT, "r_fullbright","0", "makes map very bright and renders faster"};
113
114 cvar_t r_fullbright_directed = {CVAR_CLIENT, "r_fullbright_directed", "0", "render fullbright things (unlit worldmodel and EF_FULLBRIGHT entities, but not fullbright shaders) using a constant light direction instead to add more depth while keeping uniform brightness"};
115 cvar_t r_fullbright_directed_ambient = {CVAR_CLIENT, "r_fullbright_directed_ambient", "0.5", "ambient light multiplier for directed fullbright"};
116 cvar_t r_fullbright_directed_diffuse = {CVAR_CLIENT, "r_fullbright_directed_diffuse", "0.75", "diffuse light multiplier for directed fullbright"};
117 cvar_t r_fullbright_directed_pitch = {CVAR_CLIENT, "r_fullbright_directed_pitch", "20", "constant pitch direction ('height') of the fake light source to use for fullbright"};
118 cvar_t r_fullbright_directed_pitch_relative = {CVAR_CLIENT, "r_fullbright_directed_pitch_relative", "0", "whether r_fullbright_directed_pitch is interpreted as absolute (0) or relative (1) pitch"};
119
120 cvar_t r_wateralpha = {CVAR_CLIENT | CVAR_SAVE, "r_wateralpha","1", "opacity of water polygons"};
121 cvar_t r_dynamic = {CVAR_CLIENT | CVAR_SAVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
122 cvar_t r_fullbrights = {CVAR_CLIENT | CVAR_SAVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
123 cvar_t r_shadows = {CVAR_CLIENT | CVAR_SAVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this); when set to 2, always cast the shadows in the direction set by r_shadows_throwdirection, otherwise use the model lighting."};
124 cvar_t r_shadows_darken = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_darken", "0.5", "how much shadowed areas will be darkened"};
125 cvar_t r_shadows_throwdistance = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
126 cvar_t r_shadows_throwdirection = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_throwdirection", "0 0 -1", "override throwing direction for r_shadows 2"};
127 cvar_t r_shadows_drawafterrtlighting = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_drawafterrtlighting", "0", "draw fake shadows AFTER realtime lightning is drawn. May be useful for simulating fast sunlight on large outdoor maps with only one noshadow rtlight. The price is less realistic appearance of dynamic light shadows."};
128 cvar_t r_shadows_castfrombmodels = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
129 cvar_t r_shadows_focus = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_focus", "0 0 0", "offset the shadowed area focus"};
130 cvar_t r_shadows_shadowmapscale = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_shadowmapscale", "0.25", "higher values increase shadowmap quality at a cost of area covered (multiply global shadowmap precision) for fake shadows. Needs shadowmapping ON."};
131 cvar_t r_shadows_shadowmapbias = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_shadowmapbias", "-1", "sets shadowmap bias for fake shadows. -1 sets the value of r_shadow_shadowmapping_bias. Needs shadowmapping ON."};
132 cvar_t r_q1bsp_skymasking = {CVAR_CLIENT, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
133 cvar_t r_polygonoffset_submodel_factor = {CVAR_CLIENT, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
134 cvar_t r_polygonoffset_submodel_offset = {CVAR_CLIENT, "r_polygonoffset_submodel_offset", "14", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
135 cvar_t r_polygonoffset_decals_factor = {CVAR_CLIENT, "r_polygonoffset_decals_factor", "0", "biases depth values of decals to prevent z-fighting artifacts"};
136 cvar_t r_polygonoffset_decals_offset = {CVAR_CLIENT, "r_polygonoffset_decals_offset", "-14", "biases depth values of decals to prevent z-fighting artifacts"};
137 cvar_t r_fog_exp2 = {CVAR_CLIENT, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"};
138 cvar_t r_fog_clear = {CVAR_CLIENT, "r_fog_clear", "1", "clears renderbuffer with fog color before render starts"};
139 cvar_t r_drawfog = {CVAR_CLIENT | CVAR_SAVE, "r_drawfog", "1", "allows one to disable fog rendering"};
140 cvar_t r_transparentdepthmasking = {CVAR_CLIENT | CVAR_SAVE, "r_transparentdepthmasking", "0", "enables depth writes on transparent meshes whose materially is normally opaque, this prevents seeing the inside of a transparent mesh"};
141 cvar_t r_transparent_sortmindist = {CVAR_CLIENT | CVAR_SAVE, "r_transparent_sortmindist", "0", "lower distance limit for transparent sorting"};
142 cvar_t r_transparent_sortmaxdist = {CVAR_CLIENT | CVAR_SAVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"};
143 cvar_t r_transparent_sortarraysize = {CVAR_CLIENT | CVAR_SAVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"};
144 cvar_t r_celshading = {CVAR_CLIENT | CVAR_SAVE, "r_celshading", "0", "cartoon-style light shading (OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9
145 cvar_t r_celoutlines = {CVAR_CLIENT | CVAR_SAVE, "r_celoutlines", "0", "cartoon-style outlines (requires r_shadow_deferred)"};
146
147 cvar_t gl_fogenable = {CVAR_CLIENT, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
148 cvar_t gl_fogdensity = {CVAR_CLIENT, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
149 cvar_t gl_fogred = {CVAR_CLIENT, "gl_fogred","0.3", "nehahra fog color red value (for Nehahra compatibility only)"};
150 cvar_t gl_foggreen = {CVAR_CLIENT, "gl_foggreen","0.3", "nehahra fog color green value (for Nehahra compatibility only)"};
151 cvar_t gl_fogblue = {CVAR_CLIENT, "gl_fogblue","0.3", "nehahra fog color blue value (for Nehahra compatibility only)"};
152 cvar_t gl_fogstart = {CVAR_CLIENT, "gl_fogstart", "0", "nehahra fog start distance (for Nehahra compatibility only)"};
153 cvar_t gl_fogend = {CVAR_CLIENT, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
154 cvar_t gl_skyclip = {CVAR_CLIENT, "gl_skyclip", "4608", "nehahra farclip distance - the real fog end (for Nehahra compatibility only)"};
155
156 cvar_t r_texture_dds_load = {CVAR_CLIENT | CVAR_SAVE, "r_texture_dds_load", "0", "load compressed dds/filename.dds texture instead of filename.tga, if the file exists (requires driver support)"};
157 cvar_t r_texture_dds_save = {CVAR_CLIENT | CVAR_SAVE, "r_texture_dds_save", "0", "save compressed dds/filename.dds texture when filename.tga is loaded, so that it can be loaded instead next time"};
158
159 cvar_t r_textureunits = {CVAR_CLIENT, "r_textureunits", "32", "number of texture units to use in GL 1.1 and GL 1.3 rendering paths"};
160 static cvar_t gl_combine = {CVAR_CLIENT | CVAR_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"};
161 static cvar_t r_glsl = {CVAR_CLIENT | CVAR_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"};
162
163 cvar_t r_usedepthtextures = {CVAR_CLIENT | CVAR_SAVE, "r_usedepthtextures", "1", "use depth texture instead of depth renderbuffer where possible, uses less video memory but may render slower (or faster) depending on hardware"};
164 cvar_t r_viewfbo = {CVAR_CLIENT | CVAR_SAVE, "r_viewfbo", "0", "enables use of an 8bit (1) or 16bit (2) or 32bit (3) per component float framebuffer render, which may be at a different resolution than the video mode"};
165 cvar_t r_rendertarget_debug = {CVAR_CLIENT, "r_rendertarget_debug", "-1", "replaces the view with the contents of the specified render target (by number - note that these can fluctuate depending on scene)"};
166 cvar_t r_viewscale = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale", "1", "scaling factor for resolution of the fbo rendering method, must be > 0, can be above 1 for a costly antialiasing behavior, typical values are 0.5 for 1/4th as many pixels rendered, or 1 for normal rendering"};
167 cvar_t r_viewscale_fpsscaling = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling", "0", "change resolution based on framerate"};
168 cvar_t r_viewscale_fpsscaling_min = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_min", "0.0625", "worst acceptable quality"};
169 cvar_t r_viewscale_fpsscaling_multiply = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_multiply", "5", "adjust quality up or down by the frametime difference from 1.0/target, multiplied by this factor"};
170 cvar_t r_viewscale_fpsscaling_stepsize = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_stepsize", "0.01", "smallest adjustment to hit the target framerate (this value prevents minute oscillations)"};
171 cvar_t r_viewscale_fpsscaling_stepmax = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_stepmax", "1.00", "largest adjustment to hit the target framerate (this value prevents wild overshooting of the estimate)"};
172 cvar_t r_viewscale_fpsscaling_target = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_target", "70", "desired framerate"};
173
174 cvar_t r_glsl_skeletal = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_skeletal", "1", "render skeletal models faster using a gpu-skinning technique"};
175 cvar_t r_glsl_deluxemapping = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
176 cvar_t r_glsl_offsetmapping = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
177 cvar_t r_glsl_offsetmapping_steps = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_steps", "2", "offset mapping steps (note: too high values may be not supported by your GPU)"};
178 cvar_t r_glsl_offsetmapping_reliefmapping = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
179 cvar_t r_glsl_offsetmapping_reliefmapping_steps = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_steps", "10", "relief mapping steps (note: too high values may be not supported by your GPU)"};
180 cvar_t r_glsl_offsetmapping_reliefmapping_refinesteps = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_refinesteps", "5", "relief mapping refine steps (these are a binary search executed as the last step as given by r_glsl_offsetmapping_reliefmapping_steps)"};
181 cvar_t r_glsl_offsetmapping_scale = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
182 cvar_t r_glsl_offsetmapping_lod = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_lod", "0", "apply distance-based level-of-detail correction to number of offsetmappig steps, effectively making it render faster on large open-area maps"};
183 cvar_t r_glsl_offsetmapping_lod_distance = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_lod_distance", "32", "first LOD level distance, second level (-50% steps) is 2x of this, third (33%) - 3x etc."};
184 cvar_t r_glsl_postprocess = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess", "0", "use a GLSL postprocessing shader"};
185 cvar_t r_glsl_postprocess_uservec1 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec1", "0 0 0 0", "a 4-component vector to pass as uservec1 to the postprocessing shader (only useful if default.glsl has been customized)"};
186 cvar_t r_glsl_postprocess_uservec2 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec2", "0 0 0 0", "a 4-component vector to pass as uservec2 to the postprocessing shader (only useful if default.glsl has been customized)"};
187 cvar_t r_glsl_postprocess_uservec3 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec3", "0 0 0 0", "a 4-component vector to pass as uservec3 to the postprocessing shader (only useful if default.glsl has been customized)"};
188 cvar_t r_glsl_postprocess_uservec4 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec4", "0 0 0 0", "a 4-component vector to pass as uservec4 to the postprocessing shader (only useful if default.glsl has been customized)"};
189 cvar_t r_glsl_postprocess_uservec1_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec1_enable", "1", "enables postprocessing uservec1 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
190 cvar_t r_glsl_postprocess_uservec2_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec2_enable", "1", "enables postprocessing uservec2 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
191 cvar_t r_glsl_postprocess_uservec3_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec3_enable", "1", "enables postprocessing uservec3 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
192 cvar_t r_glsl_postprocess_uservec4_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec4_enable", "1", "enables postprocessing uservec4 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
193 cvar_t r_colorfringe = {CVAR_CLIENT | CVAR_SAVE, "r_colorfringe", "0", "Chromatic aberration. Values higher than 0.025 will noticeably distort the image"};
194
195 cvar_t r_water = {CVAR_CLIENT | CVAR_SAVE, "r_water", "0", "whether to use reflections and refraction on water surfaces (note: r_wateralpha must be set below 1)"};
196 cvar_t r_water_cameraentitiesonly = {CVAR_CLIENT | CVAR_SAVE, "r_water_cameraentitiesonly", "0", "whether to only show QC-defined reflections/refractions (typically used for camera- or portal-like effects)"};
197 cvar_t r_water_clippingplanebias = {CVAR_CLIENT | CVAR_SAVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
198 cvar_t r_water_resolutionmultiplier = {CVAR_CLIENT | CVAR_SAVE, "r_water_resolutionmultiplier", "0.5", "multiplier for screen resolution when rendering refracted/reflected scenes, 1 is full quality, lower values are faster"};
199 cvar_t r_water_refractdistort = {CVAR_CLIENT | CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
200 cvar_t r_water_reflectdistort = {CVAR_CLIENT | CVAR_SAVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
201 cvar_t r_water_scissormode = {CVAR_CLIENT, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
202 cvar_t r_water_lowquality = {CVAR_CLIENT, "r_water_lowquality", "0", "special option to accelerate water rendering: 1 disables all dynamic lights, 2 disables particles too"};
203 cvar_t r_water_hideplayer = {CVAR_CLIENT | CVAR_SAVE, "r_water_hideplayer", "0", "if set to 1 then player will be hidden in refraction views, if set to 2 then player will also be hidden in reflection views, player is always visible in camera views"};
204
205 cvar_t r_lerpsprites = {CVAR_CLIENT | CVAR_SAVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"};
206 cvar_t r_lerpmodels = {CVAR_CLIENT | CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
207 cvar_t r_lerplightstyles = {CVAR_CLIENT | CVAR_SAVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
208 cvar_t r_waterscroll = {CVAR_CLIENT | CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
209
210 cvar_t r_bloom = {CVAR_CLIENT | CVAR_SAVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
211 cvar_t r_bloom_colorscale = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorscale", "1", "how bright the glow is"};
212
213 cvar_t r_bloom_brighten = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_brighten", "2", "how bright the glow is, after subtract/power"};
214 cvar_t r_bloom_blur = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_blur", "4", "how large the glow is"};
215 cvar_t r_bloom_resolution = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
216 cvar_t r_bloom_colorexponent = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorexponent", "1", "how exaggerated the glow is"};
217 cvar_t r_bloom_colorsubtract = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorsubtract", "0.125", "reduces bloom colors by a certain amount"};
218 cvar_t r_bloom_scenebrightness = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_scenebrightness", "1", "global rendering brightness when bloom is enabled"};
219
220 cvar_t r_hdr_scenebrightness = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
221 cvar_t r_hdr_glowintensity = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
222 cvar_t r_hdr_irisadaptation = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation", "0", "adjust scene brightness according to light intensity at player location"};
223 cvar_t r_hdr_irisadaptation_multiplier = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_multiplier", "2", "brightness at which value will be 1.0"};
224 cvar_t r_hdr_irisadaptation_minvalue = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_minvalue", "0.5", "minimum value that can result from multiplier / brightness"};
225 cvar_t r_hdr_irisadaptation_maxvalue = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_maxvalue", "4", "maximum value that can result from multiplier / brightness"};
226 cvar_t r_hdr_irisadaptation_value = {CVAR_CLIENT, "r_hdr_irisadaptation_value", "1", "current value as scenebrightness multiplier, changes continuously when irisadaptation is active"};
227 cvar_t r_hdr_irisadaptation_fade_up = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_fade_up", "0.1", "fade rate at which value adjusts to darkness"};
228 cvar_t r_hdr_irisadaptation_fade_down = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_fade_down", "0.5", "fade rate at which value adjusts to brightness"};
229 cvar_t r_hdr_irisadaptation_radius = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_radius", "15", "lighting within this many units of the eye is averaged"};
230
231 cvar_t r_smoothnormals_areaweighting = {CVAR_CLIENT, "r_smoothnormals_areaweighting", "1", "uses significantly faster (and supposedly higher quality) area-weighted vertex normals and tangent vectors rather than summing normalized triangle normals and tangents"};
232
233 cvar_t developer_texturelogging = {CVAR_CLIENT, "developer_texturelogging", "0", "produces a textures.log file containing names of skins and map textures the engine tried to load"};
234
235 cvar_t gl_lightmaps = {CVAR_CLIENT, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers), a value of 2 keeps normalmap shading"};
236
237 cvar_t r_test = {CVAR_CLIENT, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
238
239 cvar_t r_batch_multidraw = {CVAR_CLIENT | CVAR_SAVE, "r_batch_multidraw", "1", "issue multiple glDrawElements calls when rendering a batch of surfaces with the same texture (otherwise the index data is copied to make it one draw)"};
240 cvar_t r_batch_multidraw_mintriangles = {CVAR_CLIENT | CVAR_SAVE, "r_batch_multidraw_mintriangles", "0", "minimum number of triangles to activate multidraw path (copying small groups of triangles may be faster)"};
241 cvar_t r_batch_debugdynamicvertexpath = {CVAR_CLIENT | CVAR_SAVE, "r_batch_debugdynamicvertexpath", "0", "force the dynamic batching code path for debugging purposes"};
242 cvar_t r_batch_dynamicbuffer = {CVAR_CLIENT | CVAR_SAVE, "r_batch_dynamicbuffer", "0", "use vertex/index buffers for drawing dynamic and copytriangles batches"};
243
244 cvar_t r_glsl_saturation = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
245 cvar_t r_glsl_saturation_redcompensate = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_saturation_redcompensate", "0", "a 'vampire sight' addition to desaturation effect, does compensation for red color, r_glsl_restart is required"};
246
247 cvar_t r_glsl_vertextextureblend_usebothalphas = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_vertextextureblend_usebothalphas", "0", "use both alpha layers on vertex blended surfaces, each alpha layer sets amount of 'blend leak' on another layer, requires mod_q3shader_force_terrain_alphaflag on."};
248
249 cvar_t r_framedatasize = {CVAR_CLIENT | CVAR_SAVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"};
250 cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
251 {
252         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"},
253         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"},
254         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"},
255         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
256 };
257
258 extern cvar_t v_glslgamma_2d;
259
260 extern qboolean v_flipped_state;
261
262 r_framebufferstate_t r_fb;
263
264 /// shadow volume bsp struct with automatically growing nodes buffer
265 svbsp_t r_svbsp;
266
267 int r_uniformbufferalignment = 32; // dynamically updated to match GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
268
269 rtexture_t *r_texture_blanknormalmap;
270 rtexture_t *r_texture_white;
271 rtexture_t *r_texture_grey128;
272 rtexture_t *r_texture_black;
273 rtexture_t *r_texture_notexture;
274 rtexture_t *r_texture_whitecube;
275 rtexture_t *r_texture_normalizationcube;
276 rtexture_t *r_texture_fogattenuation;
277 rtexture_t *r_texture_fogheighttexture;
278 rtexture_t *r_texture_gammaramps;
279 unsigned int r_texture_gammaramps_serial;
280 //rtexture_t *r_texture_fogintensity;
281 rtexture_t *r_texture_reflectcube;
282
283 // TODO: hash lookups?
284 typedef struct cubemapinfo_s
285 {
286         char basename[64];
287         rtexture_t *texture;
288 }
289 cubemapinfo_t;
290
291 int r_texture_numcubemaps;
292 cubemapinfo_t *r_texture_cubemaps[MAX_CUBEMAPS];
293
294 unsigned int r_queries[MAX_OCCLUSION_QUERIES];
295 unsigned int r_numqueries;
296 unsigned int r_maxqueries;
297
298 typedef struct r_qwskincache_s
299 {
300         char name[MAX_QPATH];
301         skinframe_t *skinframe;
302 }
303 r_qwskincache_t;
304
305 static r_qwskincache_t *r_qwskincache;
306 static int r_qwskincache_size;
307
308 /// vertex coordinates for a quad that covers the screen exactly
309 extern const float r_screenvertex3f[12];
310 const float r_screenvertex3f[12] =
311 {
312         0, 0, 0,
313         1, 0, 0,
314         1, 1, 0,
315         0, 1, 0
316 };
317
318 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
319 {
320         int i;
321         for (i = 0;i < verts;i++)
322         {
323                 out[0] = in[0] * r;
324                 out[1] = in[1] * g;
325                 out[2] = in[2] * b;
326                 out[3] = in[3];
327                 in += 4;
328                 out += 4;
329         }
330 }
331
332 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
333 {
334         int i;
335         for (i = 0;i < verts;i++)
336         {
337                 out[0] = r;
338                 out[1] = g;
339                 out[2] = b;
340                 out[3] = a;
341                 out += 4;
342         }
343 }
344
345 // FIXME: move this to client?
346 void FOG_clear(void)
347 {
348         if (gamemode == GAME_NEHAHRA)
349         {
350                 Cvar_Set(&cvars_all, "gl_fogenable", "0");
351                 Cvar_Set(&cvars_all, "gl_fogdensity", "0.2");
352                 Cvar_Set(&cvars_all, "gl_fogred", "0.3");
353                 Cvar_Set(&cvars_all, "gl_foggreen", "0.3");
354                 Cvar_Set(&cvars_all, "gl_fogblue", "0.3");
355         }
356         r_refdef.fog_density = 0;
357         r_refdef.fog_red = 0;
358         r_refdef.fog_green = 0;
359         r_refdef.fog_blue = 0;
360         r_refdef.fog_alpha = 1;
361         r_refdef.fog_start = 0;
362         r_refdef.fog_end = 16384;
363         r_refdef.fog_height = 1<<30;
364         r_refdef.fog_fadedepth = 128;
365         memset(r_refdef.fog_height_texturename, 0, sizeof(r_refdef.fog_height_texturename));
366 }
367
368 static void R_BuildBlankTextures(void)
369 {
370         unsigned char data[4];
371         data[2] = 128; // normal X
372         data[1] = 128; // normal Y
373         data[0] = 255; // normal Z
374         data[3] = 255; // height
375         r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
376         data[0] = 255;
377         data[1] = 255;
378         data[2] = 255;
379         data[3] = 255;
380         r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
381         data[0] = 128;
382         data[1] = 128;
383         data[2] = 128;
384         data[3] = 255;
385         r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
386         data[0] = 0;
387         data[1] = 0;
388         data[2] = 0;
389         data[3] = 255;
390         r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
391 }
392
393 static void R_BuildNoTexture(void)
394 {
395         int x, y;
396         unsigned char pix[16][16][4];
397         // this makes a light grey/dark grey checkerboard texture
398         for (y = 0;y < 16;y++)
399         {
400                 for (x = 0;x < 16;x++)
401                 {
402                         if ((y < 8) ^ (x < 8))
403                         {
404                                 pix[y][x][0] = 128;
405                                 pix[y][x][1] = 128;
406                                 pix[y][x][2] = 128;
407                                 pix[y][x][3] = 255;
408                         }
409                         else
410                         {
411                                 pix[y][x][0] = 64;
412                                 pix[y][x][1] = 64;
413                                 pix[y][x][2] = 64;
414                                 pix[y][x][3] = 255;
415                         }
416                 }
417         }
418         r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, -1, NULL);
419 }
420
421 static void R_BuildWhiteCube(void)
422 {
423         unsigned char data[6*1*1*4];
424         memset(data, 255, sizeof(data));
425         r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
426 }
427
428 static void R_BuildNormalizationCube(void)
429 {
430         int x, y, side;
431         vec3_t v;
432         vec_t s, t, intensity;
433 #define NORMSIZE 64
434         unsigned char *data;
435         data = (unsigned char *)Mem_Alloc(tempmempool, 6*NORMSIZE*NORMSIZE*4);
436         for (side = 0;side < 6;side++)
437         {
438                 for (y = 0;y < NORMSIZE;y++)
439                 {
440                         for (x = 0;x < NORMSIZE;x++)
441                         {
442                                 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
443                                 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
444                                 switch(side)
445                                 {
446                                 default:
447                                 case 0:
448                                         v[0] = 1;
449                                         v[1] = -t;
450                                         v[2] = -s;
451                                         break;
452                                 case 1:
453                                         v[0] = -1;
454                                         v[1] = -t;
455                                         v[2] = s;
456                                         break;
457                                 case 2:
458                                         v[0] = s;
459                                         v[1] = 1;
460                                         v[2] = t;
461                                         break;
462                                 case 3:
463                                         v[0] = s;
464                                         v[1] = -1;
465                                         v[2] = -t;
466                                         break;
467                                 case 4:
468                                         v[0] = s;
469                                         v[1] = -t;
470                                         v[2] = 1;
471                                         break;
472                                 case 5:
473                                         v[0] = -s;
474                                         v[1] = -t;
475                                         v[2] = -1;
476                                         break;
477                                 }
478                                 intensity = 127.0f / sqrt(DotProduct(v, v));
479                                 data[((side*64+y)*64+x)*4+2] = (unsigned char)(128.0f + intensity * v[0]);
480                                 data[((side*64+y)*64+x)*4+1] = (unsigned char)(128.0f + intensity * v[1]);
481                                 data[((side*64+y)*64+x)*4+0] = (unsigned char)(128.0f + intensity * v[2]);
482                                 data[((side*64+y)*64+x)*4+3] = 255;
483                         }
484                 }
485         }
486         r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
487         Mem_Free(data);
488 }
489
490 static void R_BuildFogTexture(void)
491 {
492         int x, b;
493 #define FOGWIDTH 256
494         unsigned char data1[FOGWIDTH][4];
495         //unsigned char data2[FOGWIDTH][4];
496         double d, r, alpha;
497
498         r_refdef.fogmasktable_start = r_refdef.fog_start;
499         r_refdef.fogmasktable_alpha = r_refdef.fog_alpha;
500         r_refdef.fogmasktable_range = r_refdef.fogrange;
501         r_refdef.fogmasktable_density = r_refdef.fog_density;
502
503         r = r_refdef.fogmasktable_range / FOGMASKTABLEWIDTH;
504         for (x = 0;x < FOGMASKTABLEWIDTH;x++)
505         {
506                 d = (x * r - r_refdef.fogmasktable_start);
507                 if(developer_extra.integer)
508                         Con_DPrintf("%f ", d);
509                 d = max(0, d);
510                 if (r_fog_exp2.integer)
511                         alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d);
512                 else
513                         alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d);
514                 if(developer_extra.integer)
515                         Con_DPrintf(" : %f ", alpha);
516                 alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha;
517                 if(developer_extra.integer)
518                         Con_DPrintf(" = %f\n", alpha);
519                 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
520         }
521
522         for (x = 0;x < FOGWIDTH;x++)
523         {
524                 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
525                 data1[x][0] = b;
526                 data1[x][1] = b;
527                 data1[x][2] = b;
528                 data1[x][3] = 255;
529                 //data2[x][0] = 255 - b;
530                 //data2[x][1] = 255 - b;
531                 //data2[x][2] = 255 - b;
532                 //data2[x][3] = 255;
533         }
534         if (r_texture_fogattenuation)
535         {
536                 R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
537                 //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
538         }
539         else
540         {
541                 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
542                 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
543         }
544 }
545
546 static void R_BuildFogHeightTexture(void)
547 {
548         unsigned char *inpixels;
549         int size;
550         int x;
551         int y;
552         int j;
553         float c[4];
554         float f;
555         inpixels = NULL;
556         strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename));
557         if (r_refdef.fogheighttexturename[0])
558                 inpixels = loadimagepixelsbgra(r_refdef.fogheighttexturename, true, false, false, NULL);
559         if (!inpixels)
560         {
561                 r_refdef.fog_height_tablesize = 0;
562                 if (r_texture_fogheighttexture)
563                         R_FreeTexture(r_texture_fogheighttexture);
564                 r_texture_fogheighttexture = NULL;
565                 if (r_refdef.fog_height_table2d)
566                         Mem_Free(r_refdef.fog_height_table2d);
567                 r_refdef.fog_height_table2d = NULL;
568                 if (r_refdef.fog_height_table1d)
569                         Mem_Free(r_refdef.fog_height_table1d);
570                 r_refdef.fog_height_table1d = NULL;
571                 return;
572         }
573         size = image_width;
574         r_refdef.fog_height_tablesize = size;
575         r_refdef.fog_height_table1d = (unsigned char *)Mem_Alloc(r_main_mempool, size * 4);
576         r_refdef.fog_height_table2d = (unsigned char *)Mem_Alloc(r_main_mempool, size * size * 4);
577         memcpy(r_refdef.fog_height_table1d, inpixels, size * 4);
578         Mem_Free(inpixels);
579         // LadyHavoc: now the magic - what is that table2d for?  it is a cooked
580         // average fog color table accounting for every fog layer between a point
581         // and the camera.  (Note: attenuation is handled separately!)
582         for (y = 0;y < size;y++)
583         {
584                 for (x = 0;x < size;x++)
585                 {
586                         Vector4Clear(c);
587                         f = 0;
588                         if (x < y)
589                         {
590                                 for (j = x;j <= y;j++)
591                                 {
592                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
593                                         f++;
594                                 }
595                         }
596                         else
597                         {
598                                 for (j = x;j >= y;j--)
599                                 {
600                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
601                                         f++;
602                                 }
603                         }
604                         f = 1.0f / f;
605                         r_refdef.fog_height_table2d[(y*size+x)*4+0] = (unsigned char)(c[0] * f);
606                         r_refdef.fog_height_table2d[(y*size+x)*4+1] = (unsigned char)(c[1] * f);
607                         r_refdef.fog_height_table2d[(y*size+x)*4+2] = (unsigned char)(c[2] * f);
608                         r_refdef.fog_height_table2d[(y*size+x)*4+3] = (unsigned char)(c[3] * f);
609                 }
610         }
611         r_texture_fogheighttexture = R_LoadTexture2D(r_main_texturepool, "fogheighttable", size, size, r_refdef.fog_height_table2d, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_CLAMP, -1, NULL);
612 }
613
614 //=======================================================================================================================================================
615
616 static const char *builtinshaderstrings[] =
617 {
618 #include "shader_glsl.h"
619 0
620 };
621
622 //=======================================================================================================================================================
623
624 typedef struct shaderpermutationinfo_s
625 {
626         const char *pretext;
627         const char *name;
628 }
629 shaderpermutationinfo_t;
630
631 typedef struct shadermodeinfo_s
632 {
633         const char *sourcebasename;
634         const char *extension;
635         const char **builtinshaderstrings;
636         const char *pretext;
637         const char *name;
638         char *filename;
639         char *builtinstring;
640         int builtincrc;
641 }
642 shadermodeinfo_t;
643
644 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
645 shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
646 {
647         {"#define USEDIFFUSE\n", " diffuse"},
648         {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
649         {"#define USEVIEWTINT\n", " viewtint"},
650         {"#define USECOLORMAPPING\n", " colormapping"},
651         {"#define USESATURATION\n", " saturation"},
652         {"#define USEFOGINSIDE\n", " foginside"},
653         {"#define USEFOGOUTSIDE\n", " fogoutside"},
654         {"#define USEFOGHEIGHTTEXTURE\n", " fogheighttexture"},
655         {"#define USEFOGALPHAHACK\n", " fogalphahack"},
656         {"#define USEGAMMARAMPS\n", " gammaramps"},
657         {"#define USECUBEFILTER\n", " cubefilter"},
658         {"#define USEGLOW\n", " glow"},
659         {"#define USEBLOOM\n", " bloom"},
660         {"#define USESPECULAR\n", " specular"},
661         {"#define USEPOSTPROCESSING\n", " postprocessing"},
662         {"#define USEREFLECTION\n", " reflection"},
663         {"#define USEOFFSETMAPPING\n", " offsetmapping"},
664         {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
665         {"#define USESHADOWMAP2D\n", " shadowmap2d"},
666         {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm
667         {"#define USESHADOWMAPORTHO\n", " shadowmaportho"},
668         {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
669         {"#define USEALPHAKILL\n", " alphakill"},
670         {"#define USEREFLECTCUBE\n", " reflectcube"},
671         {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"},
672         {"#define USEBOUNCEGRID\n", " bouncegrid"},
673         {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm
674         {"#define USETRIPPY\n", " trippy"},
675         {"#define USEDEPTHRGB\n", " depthrgb"},
676         {"#define USEALPHAGENVERTEX\n", " alphagenvertex"},
677         {"#define USESKELETAL\n", " skeletal"},
678         {"#define USEOCCLUDE\n", " occlude"}
679 };
680
681 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
682 shadermodeinfo_t shadermodeinfo[SHADERLANGUAGE_COUNT][SHADERMODE_COUNT] =
683 {
684         // SHADERLANGUAGE_GLSL
685         {
686                 {"combined", "glsl", builtinshaderstrings, "#define MODE_GENERIC\n", " generic"},
687                 {"combined", "glsl", builtinshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
688                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
689                 {"combined", "glsl", builtinshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
690                 {"combined", "glsl", builtinshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
691                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
692                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
693                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
694                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
695                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
696                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
697                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
698                 {"combined", "glsl", builtinshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
699                 {"combined", "glsl", builtinshaderstrings, "#define MODE_WATER\n", " water"},
700                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
701                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
702         },
703 };
704
705 struct r_glsl_permutation_s;
706 typedef struct r_glsl_permutation_s
707 {
708         /// hash lookup data
709         struct r_glsl_permutation_s *hashnext;
710         unsigned int mode;
711         dpuint64 permutation;
712
713         /// indicates if we have tried compiling this permutation already
714         qboolean compiled;
715         /// 0 if compilation failed
716         int program;
717         // texture units assigned to each detected uniform
718         int tex_Texture_First;
719         int tex_Texture_Second;
720         int tex_Texture_GammaRamps;
721         int tex_Texture_Normal;
722         int tex_Texture_Color;
723         int tex_Texture_Gloss;
724         int tex_Texture_Glow;
725         int tex_Texture_SecondaryNormal;
726         int tex_Texture_SecondaryColor;
727         int tex_Texture_SecondaryGloss;
728         int tex_Texture_SecondaryGlow;
729         int tex_Texture_Pants;
730         int tex_Texture_Shirt;
731         int tex_Texture_FogHeightTexture;
732         int tex_Texture_FogMask;
733         int tex_Texture_Lightmap;
734         int tex_Texture_Deluxemap;
735         int tex_Texture_Attenuation;
736         int tex_Texture_Cube;
737         int tex_Texture_Refraction;
738         int tex_Texture_Reflection;
739         int tex_Texture_ShadowMap2D;
740         int tex_Texture_CubeProjection;
741         int tex_Texture_ScreenNormalMap;
742         int tex_Texture_ScreenDiffuse;
743         int tex_Texture_ScreenSpecular;
744         int tex_Texture_ReflectMask;
745         int tex_Texture_ReflectCube;
746         int tex_Texture_BounceGrid;
747         /// locations of detected uniforms in program object, or -1 if not found
748         int loc_Texture_First;
749         int loc_Texture_Second;
750         int loc_Texture_GammaRamps;
751         int loc_Texture_Normal;
752         int loc_Texture_Color;
753         int loc_Texture_Gloss;
754         int loc_Texture_Glow;
755         int loc_Texture_SecondaryNormal;
756         int loc_Texture_SecondaryColor;
757         int loc_Texture_SecondaryGloss;
758         int loc_Texture_SecondaryGlow;
759         int loc_Texture_Pants;
760         int loc_Texture_Shirt;
761         int loc_Texture_FogHeightTexture;
762         int loc_Texture_FogMask;
763         int loc_Texture_Lightmap;
764         int loc_Texture_Deluxemap;
765         int loc_Texture_Attenuation;
766         int loc_Texture_Cube;
767         int loc_Texture_Refraction;
768         int loc_Texture_Reflection;
769         int loc_Texture_ShadowMap2D;
770         int loc_Texture_CubeProjection;
771         int loc_Texture_ScreenNormalMap;
772         int loc_Texture_ScreenDiffuse;
773         int loc_Texture_ScreenSpecular;
774         int loc_Texture_ReflectMask;
775         int loc_Texture_ReflectCube;
776         int loc_Texture_BounceGrid;
777         int loc_Alpha;
778         int loc_BloomBlur_Parameters;
779         int loc_ClientTime;
780         int loc_Color_Ambient;
781         int loc_Color_Diffuse;
782         int loc_Color_Specular;
783         int loc_Color_Glow;
784         int loc_Color_Pants;
785         int loc_Color_Shirt;
786         int loc_DeferredColor_Ambient;
787         int loc_DeferredColor_Diffuse;
788         int loc_DeferredColor_Specular;
789         int loc_DeferredMod_Diffuse;
790         int loc_DeferredMod_Specular;
791         int loc_DistortScaleRefractReflect;
792         int loc_EyePosition;
793         int loc_FogColor;
794         int loc_FogHeightFade;
795         int loc_FogPlane;
796         int loc_FogPlaneViewDist;
797         int loc_FogRangeRecip;
798         int loc_LightColor;
799         int loc_LightDir;
800         int loc_LightPosition;
801         int loc_OffsetMapping_ScaleSteps;
802         int loc_OffsetMapping_LodDistance;
803         int loc_OffsetMapping_Bias;
804         int loc_PixelSize;
805         int loc_ReflectColor;
806         int loc_ReflectFactor;
807         int loc_ReflectOffset;
808         int loc_RefractColor;
809         int loc_Saturation;
810         int loc_ScreenCenterRefractReflect;
811         int loc_ScreenScaleRefractReflect;
812         int loc_ScreenToDepth;
813         int loc_ShadowMap_Parameters;
814         int loc_ShadowMap_TextureScale;
815         int loc_SpecularPower;
816         int loc_Skeletal_Transform12;
817         int loc_UserVec1;
818         int loc_UserVec2;
819         int loc_UserVec3;
820         int loc_UserVec4;
821         int loc_ColorFringe;
822         int loc_ViewTintColor;
823         int loc_ViewToLight;
824         int loc_ModelToLight;
825         int loc_TexMatrix;
826         int loc_BackgroundTexMatrix;
827         int loc_ModelViewProjectionMatrix;
828         int loc_ModelViewMatrix;
829         int loc_PixelToScreenTexCoord;
830         int loc_ModelToReflectCube;
831         int loc_ShadowMapMatrix;
832         int loc_BloomColorSubtract;
833         int loc_NormalmapScrollBlend;
834         int loc_BounceGridMatrix;
835         int loc_BounceGridIntensity;
836         /// uniform block bindings
837         int ubibind_Skeletal_Transform12_UniformBlock;
838         /// uniform block indices
839         int ubiloc_Skeletal_Transform12_UniformBlock;
840 }
841 r_glsl_permutation_t;
842
843 #define SHADERPERMUTATION_HASHSIZE 256
844
845
846 // non-degradable "lightweight" shader parameters to keep the permutations simpler
847 // these can NOT degrade! only use for simple stuff
848 enum
849 {
850         SHADERSTATICPARM_SATURATION_REDCOMPENSATE = 0, ///< red compensation filter for saturation
851         SHADERSTATICPARM_EXACTSPECULARMATH = 1, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
852         SHADERSTATICPARM_POSTPROCESS_USERVEC1 = 2, ///< postprocess uservec1 is enabled
853         SHADERSTATICPARM_POSTPROCESS_USERVEC2 = 3, ///< postprocess uservec2 is enabled
854         SHADERSTATICPARM_POSTPROCESS_USERVEC3 = 4, ///< postprocess uservec3 is enabled
855         SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5,  ///< postprocess uservec4 is enabled
856         SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending
857         SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7,  ///< LOD for offsetmapping
858         SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1
859         SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2
860         SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
861         SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
862         SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
863         SHADERSTATICPARM_FXAA = 13 ///< fast approximate anti aliasing
864 };
865 #define SHADERSTATICPARMS_COUNT 14
866
867 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
868 static int shaderstaticparms_count = 0;
869
870 static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0};
871 #define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F))
872
873 extern qboolean r_shadow_shadowmapsampler;
874 extern int r_shadow_shadowmappcf;
875 qboolean R_CompileShader_CheckStaticParms(void)
876 {
877         static int r_compileshader_staticparms_save[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5];
878         memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
879         memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
880
881         // detect all
882         if (r_glsl_saturation_redcompensate.integer)
883                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SATURATION_REDCOMPENSATE);
884         if (r_glsl_vertextextureblend_usebothalphas.integer)
885                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS);
886         if (r_shadow_glossexact.integer)
887                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_EXACTSPECULARMATH);
888         if (r_glsl_postprocess.integer)
889         {
890                 if (r_glsl_postprocess_uservec1_enable.integer)
891                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC1);
892                 if (r_glsl_postprocess_uservec2_enable.integer)
893                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC2);
894                 if (r_glsl_postprocess_uservec3_enable.integer)
895                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC3);
896                 if (r_glsl_postprocess_uservec4_enable.integer)
897                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
898         }
899         if (r_fxaa.integer)
900                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_FXAA);
901         if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
902                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
903
904         if (r_shadow_shadowmapsampler)
905                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER);
906         if (r_shadow_shadowmappcf > 1)
907                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2);
908         else if (r_shadow_shadowmappcf)
909                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1);
910         if (r_celshading.integer)
911                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING);
912         if (r_celoutlines.integer)
913                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES);
914
915         return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
916 }
917
918 #define R_COMPILESHADER_STATICPARM_EMIT(p, n) \
919         if(r_compileshader_staticparms[(p) >> 5] & (1 << ((p) & 0x1F))) \
920                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \
921         else \
922                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n"
923 static void R_CompileShader_AddStaticParms(unsigned int mode, dpuint64 permutation)
924 {
925         shaderstaticparms_count = 0;
926
927         // emit all
928         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SATURATION_REDCOMPENSATE, "SATURATION_REDCOMPENSATE");
929         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_EXACTSPECULARMATH, "USEEXACTSPECULARMATH");
930         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC1, "USERVEC1");
931         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC2, "USERVEC2");
932         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC3, "USERVEC3");
933         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4");
934         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS");
935         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD");
936         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1");
937         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2");
938         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
939         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
940         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
941         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
942 }
943
944 /// information about each possible shader permutation
945 r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
946 /// currently selected permutation
947 r_glsl_permutation_t *r_glsl_permutation;
948 /// storage for permutations linked in the hash table
949 memexpandablearray_t r_glsl_permutationarray;
950
951 static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, dpuint64 permutation)
952 {
953         //unsigned int hashdepth = 0;
954         unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
955         r_glsl_permutation_t *p;
956         for (p = r_glsl_permutationhash[mode][hashindex];p;p = p->hashnext)
957         {
958                 if (p->mode == mode && p->permutation == permutation)
959                 {
960                         //if (hashdepth > 10)
961                         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
962                         return p;
963                 }
964                 //hashdepth++;
965         }
966         p = (r_glsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_glsl_permutationarray);
967         p->mode = mode;
968         p->permutation = permutation;
969         p->hashnext = r_glsl_permutationhash[mode][hashindex];
970         r_glsl_permutationhash[mode][hashindex] = p;
971         //if (hashdepth > 10)
972         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
973         return p;
974 }
975
976 static char *R_ShaderStrCat(const char **strings)
977 {
978         char *string, *s;
979         const char **p = strings;
980         const char *t;
981         size_t len = 0;
982         for (p = strings;(t = *p);p++)
983                 len += strlen(t);
984         len++;
985         s = string = (char *)Mem_Alloc(r_main_mempool, len);
986         len = 0;
987         for (p = strings;(t = *p);p++)
988         {
989                 len = strlen(t);
990                 memcpy(s, t, len);
991                 s += len;
992         }
993         *s = 0;
994         return string;
995 }
996
997 static char *R_ShaderStrCat(const char **strings);
998 static void R_InitShaderModeInfo(void)
999 {
1000         int i, language;
1001         shadermodeinfo_t *modeinfo;
1002         // we have a bunch of things to compute that weren't calculated at engine compile time - all filenames should have a crc of the builtin strings to prevent accidental overrides (any customization must be updated to match engine)
1003         for (language = 0; language < SHADERLANGUAGE_COUNT; language++)
1004         {
1005                 for (i = 0; i < SHADERMODE_COUNT; i++)
1006                 {
1007                         char filename[MAX_QPATH];
1008                         modeinfo = &shadermodeinfo[language][i];
1009                         modeinfo->builtinstring = R_ShaderStrCat(modeinfo->builtinshaderstrings);
1010                         modeinfo->builtincrc = CRC_Block((const unsigned char *)modeinfo->builtinstring, strlen(modeinfo->builtinstring));
1011                         dpsnprintf(filename, sizeof(filename), "%s/%s_crc%i.%s", modeinfo->extension, modeinfo->sourcebasename, modeinfo->builtincrc, modeinfo->extension);
1012                         modeinfo->filename = Mem_strdup(r_main_mempool, filename);
1013                 }
1014         }
1015 }
1016
1017 static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qboolean printfromdisknotice, qboolean builtinonly)
1018 {
1019         char *shaderstring;
1020         // if the mode has no filename we have to return the builtin string
1021         if (builtinonly || !modeinfo->filename)
1022                 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1023         // note that FS_LoadFile appends a 0 byte to make it a valid string
1024         shaderstring = (char *)FS_LoadFile(modeinfo->filename, r_main_mempool, false, NULL);
1025         if (shaderstring)
1026         {
1027                 if (printfromdisknotice)
1028                         Con_DPrintf("Loading shaders from file %s...\n", modeinfo->filename);
1029                 return shaderstring;
1030         }
1031         // fall back to builtinstring
1032         return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1033 }
1034
1035 static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, dpuint64 permutation)
1036 {
1037         int i;
1038         int ubibind;
1039         int sampler;
1040         shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode];
1041         char *sourcestring;
1042         char permutationname[256];
1043         int vertstrings_count = 0;
1044         int geomstrings_count = 0;
1045         int fragstrings_count = 0;
1046         const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1047         const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1048         const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1049
1050         if (p->compiled)
1051                 return;
1052         p->compiled = true;
1053         p->program = 0;
1054
1055         permutationname[0] = 0;
1056         sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false);
1057
1058         strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
1059
1060         // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object)
1061         if(vid.support.glshaderversion >= 140)
1062         {
1063                 vertstrings_list[vertstrings_count++] = "#version 140\n";
1064                 geomstrings_list[geomstrings_count++] = "#version 140\n";
1065                 fragstrings_list[fragstrings_count++] = "#version 140\n";
1066                 vertstrings_list[vertstrings_count++] = "#define GLSL140\n";
1067                 geomstrings_list[geomstrings_count++] = "#define GLSL140\n";
1068                 fragstrings_list[fragstrings_count++] = "#define GLSL140\n";
1069         }
1070         // if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad)
1071         else if(vid.support.glshaderversion >= 130)
1072         {
1073                 vertstrings_list[vertstrings_count++] = "#version 130\n";
1074                 geomstrings_list[geomstrings_count++] = "#version 130\n";
1075                 fragstrings_list[fragstrings_count++] = "#version 130\n";
1076                 vertstrings_list[vertstrings_count++] = "#define GLSL130\n";
1077                 geomstrings_list[geomstrings_count++] = "#define GLSL130\n";
1078                 fragstrings_list[fragstrings_count++] = "#define GLSL130\n";
1079         }
1080         // if we can do #version 120, we should (this adds the invariant keyword)
1081         else if(vid.support.glshaderversion >= 120)
1082         {
1083                 vertstrings_list[vertstrings_count++] = "#version 120\n";
1084                 geomstrings_list[geomstrings_count++] = "#version 120\n";
1085                 fragstrings_list[fragstrings_count++] = "#version 120\n";
1086                 vertstrings_list[vertstrings_count++] = "#define GLSL120\n";
1087                 geomstrings_list[geomstrings_count++] = "#define GLSL120\n";
1088                 fragstrings_list[fragstrings_count++] = "#define GLSL120\n";
1089         }
1090         // GLES also adds several things from GLSL120
1091         switch(vid.renderpath)
1092         {
1093         case RENDERPATH_GLES2:
1094                 vertstrings_list[vertstrings_count++] = "#define GLES\n";
1095                 geomstrings_list[geomstrings_count++] = "#define GLES\n";
1096                 fragstrings_list[fragstrings_count++] = "#define GLES\n";
1097                 break;
1098         default:
1099                 break;
1100         }
1101
1102         // the first pretext is which type of shader to compile as
1103         // (later these will all be bound together as a program object)
1104         vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
1105         geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
1106         fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
1107
1108         // the second pretext is the mode (for example a light source)
1109         vertstrings_list[vertstrings_count++] = modeinfo->pretext;
1110         geomstrings_list[geomstrings_count++] = modeinfo->pretext;
1111         fragstrings_list[fragstrings_count++] = modeinfo->pretext;
1112         strlcat(permutationname, modeinfo->name, sizeof(permutationname));
1113
1114         // now add all the permutation pretexts
1115         for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1116         {
1117                 if (permutation & (1ll<<i))
1118                 {
1119                         vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
1120                         geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
1121                         fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
1122                         strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
1123                 }
1124                 else
1125                 {
1126                         // keep line numbers correct
1127                         vertstrings_list[vertstrings_count++] = "\n";
1128                         geomstrings_list[geomstrings_count++] = "\n";
1129                         fragstrings_list[fragstrings_count++] = "\n";
1130                 }
1131         }
1132
1133         // add static parms
1134         R_CompileShader_AddStaticParms(mode, permutation);
1135         memcpy((char *)(vertstrings_list + vertstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1136         vertstrings_count += shaderstaticparms_count;
1137         memcpy((char *)(geomstrings_list + geomstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1138         geomstrings_count += shaderstaticparms_count;
1139         memcpy((char *)(fragstrings_list + fragstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1140         fragstrings_count += shaderstaticparms_count;
1141
1142         // now append the shader text itself
1143         vertstrings_list[vertstrings_count++] = sourcestring;
1144         geomstrings_list[geomstrings_count++] = sourcestring;
1145         fragstrings_list[fragstrings_count++] = sourcestring;
1146
1147         // we don't currently use geometry shaders for anything, so just empty the list
1148         geomstrings_count = 0;
1149
1150         // compile the shader program
1151         if (vertstrings_count + geomstrings_count + fragstrings_count)
1152                 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1153         if (p->program)
1154         {
1155                 CHECKGLERROR
1156                 qglUseProgram(p->program);CHECKGLERROR
1157                 // look up all the uniform variable names we care about, so we don't
1158                 // have to look them up every time we set them
1159
1160 #if 0
1161                 // debugging aid
1162                 {
1163                         GLint activeuniformindex = 0;
1164                         GLint numactiveuniforms = 0;
1165                         char uniformname[128];
1166                         GLsizei uniformnamelength = 0;
1167                         GLint uniformsize = 0;
1168                         GLenum uniformtype = 0;
1169                         memset(uniformname, 0, sizeof(uniformname));
1170                         qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms);
1171                         Con_Printf("Shader has %i uniforms\n", numactiveuniforms);
1172                         for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++)
1173                         {
1174                                 qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname);
1175                                 Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype);
1176                         }
1177                 }
1178 #endif
1179
1180                 p->loc_Texture_First              = qglGetUniformLocation(p->program, "Texture_First");
1181                 p->loc_Texture_Second             = qglGetUniformLocation(p->program, "Texture_Second");
1182                 p->loc_Texture_GammaRamps         = qglGetUniformLocation(p->program, "Texture_GammaRamps");
1183                 p->loc_Texture_Normal             = qglGetUniformLocation(p->program, "Texture_Normal");
1184                 p->loc_Texture_Color              = qglGetUniformLocation(p->program, "Texture_Color");
1185                 p->loc_Texture_Gloss              = qglGetUniformLocation(p->program, "Texture_Gloss");
1186                 p->loc_Texture_Glow               = qglGetUniformLocation(p->program, "Texture_Glow");
1187                 p->loc_Texture_SecondaryNormal    = qglGetUniformLocation(p->program, "Texture_SecondaryNormal");
1188                 p->loc_Texture_SecondaryColor     = qglGetUniformLocation(p->program, "Texture_SecondaryColor");
1189                 p->loc_Texture_SecondaryGloss     = qglGetUniformLocation(p->program, "Texture_SecondaryGloss");
1190                 p->loc_Texture_SecondaryGlow      = qglGetUniformLocation(p->program, "Texture_SecondaryGlow");
1191                 p->loc_Texture_Pants              = qglGetUniformLocation(p->program, "Texture_Pants");
1192                 p->loc_Texture_Shirt              = qglGetUniformLocation(p->program, "Texture_Shirt");
1193                 p->loc_Texture_FogHeightTexture   = qglGetUniformLocation(p->program, "Texture_FogHeightTexture");
1194                 p->loc_Texture_FogMask            = qglGetUniformLocation(p->program, "Texture_FogMask");
1195                 p->loc_Texture_Lightmap           = qglGetUniformLocation(p->program, "Texture_Lightmap");
1196                 p->loc_Texture_Deluxemap          = qglGetUniformLocation(p->program, "Texture_Deluxemap");
1197                 p->loc_Texture_Attenuation        = qglGetUniformLocation(p->program, "Texture_Attenuation");
1198                 p->loc_Texture_Cube               = qglGetUniformLocation(p->program, "Texture_Cube");
1199                 p->loc_Texture_Refraction         = qglGetUniformLocation(p->program, "Texture_Refraction");
1200                 p->loc_Texture_Reflection         = qglGetUniformLocation(p->program, "Texture_Reflection");
1201                 p->loc_Texture_ShadowMap2D        = qglGetUniformLocation(p->program, "Texture_ShadowMap2D");
1202                 p->loc_Texture_CubeProjection     = qglGetUniformLocation(p->program, "Texture_CubeProjection");
1203                 p->loc_Texture_ScreenNormalMap    = qglGetUniformLocation(p->program, "Texture_ScreenNormalMap");
1204                 p->loc_Texture_ScreenDiffuse      = qglGetUniformLocation(p->program, "Texture_ScreenDiffuse");
1205                 p->loc_Texture_ScreenSpecular     = qglGetUniformLocation(p->program, "Texture_ScreenSpecular");
1206                 p->loc_Texture_ReflectMask        = qglGetUniformLocation(p->program, "Texture_ReflectMask");
1207                 p->loc_Texture_ReflectCube        = qglGetUniformLocation(p->program, "Texture_ReflectCube");
1208                 p->loc_Texture_BounceGrid         = qglGetUniformLocation(p->program, "Texture_BounceGrid");
1209                 p->loc_Alpha                      = qglGetUniformLocation(p->program, "Alpha");
1210                 p->loc_BloomBlur_Parameters       = qglGetUniformLocation(p->program, "BloomBlur_Parameters");
1211                 p->loc_ClientTime                 = qglGetUniformLocation(p->program, "ClientTime");
1212                 p->loc_Color_Ambient              = qglGetUniformLocation(p->program, "Color_Ambient");
1213                 p->loc_Color_Diffuse              = qglGetUniformLocation(p->program, "Color_Diffuse");
1214                 p->loc_Color_Specular             = qglGetUniformLocation(p->program, "Color_Specular");
1215                 p->loc_Color_Glow                 = qglGetUniformLocation(p->program, "Color_Glow");
1216                 p->loc_Color_Pants                = qglGetUniformLocation(p->program, "Color_Pants");
1217                 p->loc_Color_Shirt                = qglGetUniformLocation(p->program, "Color_Shirt");
1218                 p->loc_DeferredColor_Ambient      = qglGetUniformLocation(p->program, "DeferredColor_Ambient");
1219                 p->loc_DeferredColor_Diffuse      = qglGetUniformLocation(p->program, "DeferredColor_Diffuse");
1220                 p->loc_DeferredColor_Specular     = qglGetUniformLocation(p->program, "DeferredColor_Specular");
1221                 p->loc_DeferredMod_Diffuse        = qglGetUniformLocation(p->program, "DeferredMod_Diffuse");
1222                 p->loc_DeferredMod_Specular       = qglGetUniformLocation(p->program, "DeferredMod_Specular");
1223                 p->loc_DistortScaleRefractReflect = qglGetUniformLocation(p->program, "DistortScaleRefractReflect");
1224                 p->loc_EyePosition                = qglGetUniformLocation(p->program, "EyePosition");
1225                 p->loc_FogColor                   = qglGetUniformLocation(p->program, "FogColor");
1226                 p->loc_FogHeightFade              = qglGetUniformLocation(p->program, "FogHeightFade");
1227                 p->loc_FogPlane                   = qglGetUniformLocation(p->program, "FogPlane");
1228                 p->loc_FogPlaneViewDist           = qglGetUniformLocation(p->program, "FogPlaneViewDist");
1229                 p->loc_FogRangeRecip              = qglGetUniformLocation(p->program, "FogRangeRecip");
1230                 p->loc_LightColor                 = qglGetUniformLocation(p->program, "LightColor");
1231                 p->loc_LightDir                   = qglGetUniformLocation(p->program, "LightDir");
1232                 p->loc_LightPosition              = qglGetUniformLocation(p->program, "LightPosition");
1233                 p->loc_OffsetMapping_ScaleSteps   = qglGetUniformLocation(p->program, "OffsetMapping_ScaleSteps");
1234                 p->loc_OffsetMapping_LodDistance  = qglGetUniformLocation(p->program, "OffsetMapping_LodDistance");
1235                 p->loc_OffsetMapping_Bias         = qglGetUniformLocation(p->program, "OffsetMapping_Bias");
1236                 p->loc_PixelSize                  = qglGetUniformLocation(p->program, "PixelSize");
1237                 p->loc_ReflectColor               = qglGetUniformLocation(p->program, "ReflectColor");
1238                 p->loc_ReflectFactor              = qglGetUniformLocation(p->program, "ReflectFactor");
1239                 p->loc_ReflectOffset              = qglGetUniformLocation(p->program, "ReflectOffset");
1240                 p->loc_RefractColor               = qglGetUniformLocation(p->program, "RefractColor");
1241                 p->loc_Saturation                 = qglGetUniformLocation(p->program, "Saturation");
1242                 p->loc_ScreenCenterRefractReflect = qglGetUniformLocation(p->program, "ScreenCenterRefractReflect");
1243                 p->loc_ScreenScaleRefractReflect  = qglGetUniformLocation(p->program, "ScreenScaleRefractReflect");
1244                 p->loc_ScreenToDepth              = qglGetUniformLocation(p->program, "ScreenToDepth");
1245                 p->loc_ShadowMap_Parameters       = qglGetUniformLocation(p->program, "ShadowMap_Parameters");
1246                 p->loc_ShadowMap_TextureScale     = qglGetUniformLocation(p->program, "ShadowMap_TextureScale");
1247                 p->loc_SpecularPower              = qglGetUniformLocation(p->program, "SpecularPower");
1248                 p->loc_UserVec1                   = qglGetUniformLocation(p->program, "UserVec1");
1249                 p->loc_UserVec2                   = qglGetUniformLocation(p->program, "UserVec2");
1250                 p->loc_UserVec3                   = qglGetUniformLocation(p->program, "UserVec3");
1251                 p->loc_UserVec4                   = qglGetUniformLocation(p->program, "UserVec4");
1252                 p->loc_ColorFringe                = qglGetUniformLocation(p->program, "ColorFringe");
1253                 p->loc_ViewTintColor              = qglGetUniformLocation(p->program, "ViewTintColor");
1254                 p->loc_ViewToLight                = qglGetUniformLocation(p->program, "ViewToLight");
1255                 p->loc_ModelToLight               = qglGetUniformLocation(p->program, "ModelToLight");
1256                 p->loc_TexMatrix                  = qglGetUniformLocation(p->program, "TexMatrix");
1257                 p->loc_BackgroundTexMatrix        = qglGetUniformLocation(p->program, "BackgroundTexMatrix");
1258                 p->loc_ModelViewMatrix            = qglGetUniformLocation(p->program, "ModelViewMatrix");
1259                 p->loc_ModelViewProjectionMatrix  = qglGetUniformLocation(p->program, "ModelViewProjectionMatrix");
1260                 p->loc_PixelToScreenTexCoord      = qglGetUniformLocation(p->program, "PixelToScreenTexCoord");
1261                 p->loc_ModelToReflectCube         = qglGetUniformLocation(p->program, "ModelToReflectCube");
1262                 p->loc_ShadowMapMatrix            = qglGetUniformLocation(p->program, "ShadowMapMatrix");
1263                 p->loc_BloomColorSubtract         = qglGetUniformLocation(p->program, "BloomColorSubtract");
1264                 p->loc_NormalmapScrollBlend       = qglGetUniformLocation(p->program, "NormalmapScrollBlend");
1265                 p->loc_BounceGridMatrix           = qglGetUniformLocation(p->program, "BounceGridMatrix");
1266                 p->loc_BounceGridIntensity        = qglGetUniformLocation(p->program, "BounceGridIntensity");
1267                 // initialize the samplers to refer to the texture units we use
1268                 p->tex_Texture_First = -1;
1269                 p->tex_Texture_Second = -1;
1270                 p->tex_Texture_GammaRamps = -1;
1271                 p->tex_Texture_Normal = -1;
1272                 p->tex_Texture_Color = -1;
1273                 p->tex_Texture_Gloss = -1;
1274                 p->tex_Texture_Glow = -1;
1275                 p->tex_Texture_SecondaryNormal = -1;
1276                 p->tex_Texture_SecondaryColor = -1;
1277                 p->tex_Texture_SecondaryGloss = -1;
1278                 p->tex_Texture_SecondaryGlow = -1;
1279                 p->tex_Texture_Pants = -1;
1280                 p->tex_Texture_Shirt = -1;
1281                 p->tex_Texture_FogHeightTexture = -1;
1282                 p->tex_Texture_FogMask = -1;
1283                 p->tex_Texture_Lightmap = -1;
1284                 p->tex_Texture_Deluxemap = -1;
1285                 p->tex_Texture_Attenuation = -1;
1286                 p->tex_Texture_Cube = -1;
1287                 p->tex_Texture_Refraction = -1;
1288                 p->tex_Texture_Reflection = -1;
1289                 p->tex_Texture_ShadowMap2D = -1;
1290                 p->tex_Texture_CubeProjection = -1;
1291                 p->tex_Texture_ScreenNormalMap = -1;
1292                 p->tex_Texture_ScreenDiffuse = -1;
1293                 p->tex_Texture_ScreenSpecular = -1;
1294                 p->tex_Texture_ReflectMask = -1;
1295                 p->tex_Texture_ReflectCube = -1;
1296                 p->tex_Texture_BounceGrid = -1;
1297                 // bind the texture samplers in use
1298                 sampler = 0;
1299                 if (p->loc_Texture_First           >= 0) {p->tex_Texture_First            = sampler;qglUniform1i(p->loc_Texture_First           , sampler);sampler++;}
1300                 if (p->loc_Texture_Second          >= 0) {p->tex_Texture_Second           = sampler;qglUniform1i(p->loc_Texture_Second          , sampler);sampler++;}
1301                 if (p->loc_Texture_GammaRamps      >= 0) {p->tex_Texture_GammaRamps       = sampler;qglUniform1i(p->loc_Texture_GammaRamps      , sampler);sampler++;}
1302                 if (p->loc_Texture_Normal          >= 0) {p->tex_Texture_Normal           = sampler;qglUniform1i(p->loc_Texture_Normal          , sampler);sampler++;}
1303                 if (p->loc_Texture_Color           >= 0) {p->tex_Texture_Color            = sampler;qglUniform1i(p->loc_Texture_Color           , sampler);sampler++;}
1304                 if (p->loc_Texture_Gloss           >= 0) {p->tex_Texture_Gloss            = sampler;qglUniform1i(p->loc_Texture_Gloss           , sampler);sampler++;}
1305                 if (p->loc_Texture_Glow            >= 0) {p->tex_Texture_Glow             = sampler;qglUniform1i(p->loc_Texture_Glow            , sampler);sampler++;}
1306                 if (p->loc_Texture_SecondaryNormal >= 0) {p->tex_Texture_SecondaryNormal  = sampler;qglUniform1i(p->loc_Texture_SecondaryNormal , sampler);sampler++;}
1307                 if (p->loc_Texture_SecondaryColor  >= 0) {p->tex_Texture_SecondaryColor   = sampler;qglUniform1i(p->loc_Texture_SecondaryColor  , sampler);sampler++;}
1308                 if (p->loc_Texture_SecondaryGloss  >= 0) {p->tex_Texture_SecondaryGloss   = sampler;qglUniform1i(p->loc_Texture_SecondaryGloss  , sampler);sampler++;}
1309                 if (p->loc_Texture_SecondaryGlow   >= 0) {p->tex_Texture_SecondaryGlow    = sampler;qglUniform1i(p->loc_Texture_SecondaryGlow   , sampler);sampler++;}
1310                 if (p->loc_Texture_Pants           >= 0) {p->tex_Texture_Pants            = sampler;qglUniform1i(p->loc_Texture_Pants           , sampler);sampler++;}
1311                 if (p->loc_Texture_Shirt           >= 0) {p->tex_Texture_Shirt            = sampler;qglUniform1i(p->loc_Texture_Shirt           , sampler);sampler++;}
1312                 if (p->loc_Texture_FogHeightTexture>= 0) {p->tex_Texture_FogHeightTexture = sampler;qglUniform1i(p->loc_Texture_FogHeightTexture, sampler);sampler++;}
1313                 if (p->loc_Texture_FogMask         >= 0) {p->tex_Texture_FogMask          = sampler;qglUniform1i(p->loc_Texture_FogMask         , sampler);sampler++;}
1314                 if (p->loc_Texture_Lightmap        >= 0) {p->tex_Texture_Lightmap         = sampler;qglUniform1i(p->loc_Texture_Lightmap        , sampler);sampler++;}
1315                 if (p->loc_Texture_Deluxemap       >= 0) {p->tex_Texture_Deluxemap        = sampler;qglUniform1i(p->loc_Texture_Deluxemap       , sampler);sampler++;}
1316                 if (p->loc_Texture_Attenuation     >= 0) {p->tex_Texture_Attenuation      = sampler;qglUniform1i(p->loc_Texture_Attenuation     , sampler);sampler++;}
1317                 if (p->loc_Texture_Cube            >= 0) {p->tex_Texture_Cube             = sampler;qglUniform1i(p->loc_Texture_Cube            , sampler);sampler++;}
1318                 if (p->loc_Texture_Refraction      >= 0) {p->tex_Texture_Refraction       = sampler;qglUniform1i(p->loc_Texture_Refraction      , sampler);sampler++;}
1319                 if (p->loc_Texture_Reflection      >= 0) {p->tex_Texture_Reflection       = sampler;qglUniform1i(p->loc_Texture_Reflection      , sampler);sampler++;}
1320                 if (p->loc_Texture_ShadowMap2D     >= 0) {p->tex_Texture_ShadowMap2D      = sampler;qglUniform1i(p->loc_Texture_ShadowMap2D     , sampler);sampler++;}
1321                 if (p->loc_Texture_CubeProjection  >= 0) {p->tex_Texture_CubeProjection   = sampler;qglUniform1i(p->loc_Texture_CubeProjection  , sampler);sampler++;}
1322                 if (p->loc_Texture_ScreenNormalMap >= 0) {p->tex_Texture_ScreenNormalMap  = sampler;qglUniform1i(p->loc_Texture_ScreenNormalMap , sampler);sampler++;}
1323                 if (p->loc_Texture_ScreenDiffuse   >= 0) {p->tex_Texture_ScreenDiffuse    = sampler;qglUniform1i(p->loc_Texture_ScreenDiffuse   , sampler);sampler++;}
1324                 if (p->loc_Texture_ScreenSpecular  >= 0) {p->tex_Texture_ScreenSpecular   = sampler;qglUniform1i(p->loc_Texture_ScreenSpecular  , sampler);sampler++;}
1325                 if (p->loc_Texture_ReflectMask     >= 0) {p->tex_Texture_ReflectMask      = sampler;qglUniform1i(p->loc_Texture_ReflectMask     , sampler);sampler++;}
1326                 if (p->loc_Texture_ReflectCube     >= 0) {p->tex_Texture_ReflectCube      = sampler;qglUniform1i(p->loc_Texture_ReflectCube     , sampler);sampler++;}
1327                 if (p->loc_Texture_BounceGrid      >= 0) {p->tex_Texture_BounceGrid       = sampler;qglUniform1i(p->loc_Texture_BounceGrid      , sampler);sampler++;}
1328                 // get the uniform block indices so we can bind them
1329                 p->ubiloc_Skeletal_Transform12_UniformBlock = -1;
1330 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1331                 p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
1332 #endif
1333                 // clear the uniform block bindings
1334                 p->ubibind_Skeletal_Transform12_UniformBlock = -1;
1335                 // bind the uniform blocks in use
1336                 ubibind = 0;
1337 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1338                 if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;}
1339 #endif
1340                 // we're done compiling and setting up the shader, at least until it is used
1341                 CHECKGLERROR
1342                 Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler);
1343         }
1344         else
1345                 Con_Printf("^1GLSL shader %s failed!  some features may not work properly.\n", permutationname);
1346
1347         // free the strings
1348         if (sourcestring)
1349                 Mem_Free(sourcestring);
1350 }
1351
1352 static void R_SetupShader_SetPermutationGLSL(unsigned int mode, dpuint64 permutation)
1353 {
1354         r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation);
1355         if (r_glsl_permutation != perm)
1356         {
1357                 r_glsl_permutation = perm;
1358                 if (!r_glsl_permutation->program)
1359                 {
1360                         if (!r_glsl_permutation->compiled)
1361                         {
1362                                 Con_DPrintf("Compiling shader mode %u permutation %llx\n", mode, permutation);
1363                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1364                         }
1365                         if (!r_glsl_permutation->program)
1366                         {
1367                                 // remove features until we find a valid permutation
1368                                 int i;
1369                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1370                                 {
1371                                         // reduce i more quickly whenever it would not remove any bits
1372                                         dpuint64 j = 1ll<<(SHADERPERMUTATION_COUNT-1-i);
1373                                         if (!(permutation & j))
1374                                                 continue;
1375                                         permutation -= j;
1376                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1377                                         if (!r_glsl_permutation->compiled)
1378                                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1379                                         if (r_glsl_permutation->program)
1380                                                 break;
1381                                 }
1382                                 if (i >= SHADERPERMUTATION_COUNT)
1383                                 {
1384                                         //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext);
1385                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1386                                         qglUseProgram(0);CHECKGLERROR
1387                                         return; // no bit left to clear, entire mode is broken
1388                                 }
1389                         }
1390                 }
1391                 CHECKGLERROR
1392                 qglUseProgram(r_glsl_permutation->program);CHECKGLERROR
1393         }
1394         if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
1395         if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
1396         if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time);
1397         CHECKGLERROR
1398 }
1399
1400 void R_GLSL_Restart_f(cmd_state_t *cmd)
1401 {
1402         unsigned int i, limit;
1403         switch(vid.renderpath)
1404         {
1405         case RENDERPATH_GL32:
1406         case RENDERPATH_GLES2:
1407                 {
1408                         r_glsl_permutation_t *p;
1409                         r_glsl_permutation = NULL;
1410                         limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
1411                         for (i = 0;i < limit;i++)
1412                         {
1413                                 if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
1414                                 {
1415                                         GL_Backend_FreeProgram(p->program);
1416                                         Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
1417                                 }
1418                         }
1419                         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
1420                 }
1421                 break;
1422         }
1423 }
1424
1425 static void R_GLSL_DumpShader_f(cmd_state_t *cmd)
1426 {
1427         int i, language, mode, dupe;
1428         char *text;
1429         shadermodeinfo_t *modeinfo;
1430         qfile_t *file;
1431
1432         for (language = 0;language < SHADERLANGUAGE_COUNT;language++)
1433         {
1434                 modeinfo = shadermodeinfo[language];
1435                 for (mode = 0;mode < SHADERMODE_COUNT;mode++)
1436                 {
1437                         // don't dump the same file multiple times (most or all shaders come from the same file)
1438                         for (dupe = mode - 1;dupe >= 0;dupe--)
1439                                 if (!strcmp(modeinfo[mode].filename, modeinfo[dupe].filename))
1440                                         break;
1441                         if (dupe >= 0)
1442                                 continue;
1443                         text = modeinfo[mode].builtinstring;
1444                         if (!text)
1445                                 continue;
1446                         file = FS_OpenRealFile(modeinfo[mode].filename, "w", false);
1447                         if (file)
1448                         {
1449                                 FS_Print(file, "/* The engine may define the following macros:\n");
1450                                 FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
1451                                 for (i = 0;i < SHADERMODE_COUNT;i++)
1452                                         FS_Print(file, modeinfo[i].pretext);
1453                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1454                                         FS_Print(file, shaderpermutationinfo[i].pretext);
1455                                 FS_Print(file, "*/\n");
1456                                 FS_Print(file, text);
1457                                 FS_Close(file);
1458                                 Con_Printf("%s written\n", modeinfo[mode].filename);
1459                         }
1460                         else
1461                                 Con_Printf("failed to write to %s\n", modeinfo[mode].filename);
1462                 }
1463         }
1464 }
1465
1466 void R_SetupShader_Generic(rtexture_t *t, qboolean usegamma, qboolean notrippy, qboolean suppresstexalpha)
1467 {
1468         dpuint64 permutation = 0;
1469         if (r_trippy.integer && !notrippy)
1470                 permutation |= SHADERPERMUTATION_TRIPPY;
1471         permutation |= SHADERPERMUTATION_VIEWTINT;
1472         if (t)
1473                 permutation |= SHADERPERMUTATION_DIFFUSE;
1474         if (usegamma && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
1475                 permutation |= SHADERPERMUTATION_GAMMARAMPS;
1476         if (suppresstexalpha)
1477                 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1478         if (vid.allowalphatocoverage)
1479                 GL_AlphaToCoverage(false);
1480         switch (vid.renderpath)
1481         {
1482         case RENDERPATH_GL32:
1483         case RENDERPATH_GLES2:
1484                 R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation);
1485                 if (r_glsl_permutation->tex_Texture_First >= 0)
1486                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First, t);
1487                 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0)
1488                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps);
1489                 break;
1490         }
1491 }
1492
1493 void R_SetupShader_Generic_NoTexture(qboolean usegamma, qboolean notrippy)
1494 {
1495         R_SetupShader_Generic(NULL, usegamma, notrippy, false);
1496 }
1497
1498 void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb, qboolean skeletal)
1499 {
1500         dpuint64 permutation = 0;
1501         if (r_trippy.integer && !notrippy)
1502                 permutation |= SHADERPERMUTATION_TRIPPY;
1503         if (depthrgb)
1504                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1505         if (skeletal)
1506                 permutation |= SHADERPERMUTATION_SKELETAL;
1507
1508         if (vid.allowalphatocoverage)
1509                 GL_AlphaToCoverage(false);
1510         switch (vid.renderpath)
1511         {
1512         case RENDERPATH_GL32:
1513         case RENDERPATH_GLES2:
1514                 R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
1515 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1516                 if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
1517 #endif
1518                 break;
1519         }
1520 }
1521
1522 #define BLENDFUNC_ALLOWS_COLORMOD      1
1523 #define BLENDFUNC_ALLOWS_FOG           2
1524 #define BLENDFUNC_ALLOWS_FOG_HACK0     4
1525 #define BLENDFUNC_ALLOWS_FOG_HACKALPHA 8
1526 #define BLENDFUNC_ALLOWS_ANYFOG        (BLENDFUNC_ALLOWS_FOG | BLENDFUNC_ALLOWS_FOG_HACK0 | BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1527 static int R_BlendFuncFlags(int src, int dst)
1528 {
1529         int r = 0;
1530
1531         // a blendfunc allows colormod if:
1532         // a) it can never keep the destination pixel invariant, or
1533         // b) it can keep the destination pixel invariant, and still can do so if colormodded
1534         // this is to prevent unintended side effects from colormod
1535
1536         // a blendfunc allows fog if:
1537         // blend(fog(src), fog(dst)) == fog(blend(src, dst))
1538         // this is to prevent unintended side effects from fog
1539
1540         // these checks are the output of fogeval.pl
1541
1542         r |= BLENDFUNC_ALLOWS_COLORMOD;
1543         if(src == GL_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1544         if(src == GL_DST_ALPHA && dst == GL_ONE_MINUS_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1545         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1546         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1547         if(src == GL_DST_COLOR && dst == GL_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1548         if(src == GL_DST_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1549         if(src == GL_DST_COLOR && dst == GL_ZERO) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1550         if(src == GL_ONE && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1551         if(src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG_HACKALPHA;
1552         if(src == GL_ONE && dst == GL_ZERO) r |= BLENDFUNC_ALLOWS_FOG;
1553         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1554         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1555         if(src == GL_ONE_MINUS_DST_COLOR && dst == GL_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1556         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1557         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1558         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1559         if(src == GL_ONE_MINUS_SRC_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1560         if(src == GL_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1561         if(src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1562         if(src == GL_ZERO && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG;
1563         if(src == GL_ZERO && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1564
1565         return r;
1566 }
1567
1568 void R_SetupShader_Surface(const float rtlightambient[3], const float rtlightdiffuse[3], const float rtlightspecular[3], rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist, void *surfacewaterplane, qboolean notrippy)
1569 {
1570         // select a permutation of the lighting shader appropriate to this
1571         // combination of texture, entity, light source, and fogging, only use the
1572         // minimum features necessary to avoid wasting rendering time in the
1573         // fragment shader on features that are not being used
1574         dpuint64 permutation = 0;
1575         unsigned int mode = 0;
1576         int blendfuncflags;
1577         texture_t *t = rsurface.texture;
1578         float m16f[16];
1579         matrix4x4_t tempmatrix;
1580         r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
1581         if (r_trippy.integer && !notrippy)
1582                 permutation |= SHADERPERMUTATION_TRIPPY;
1583         if (t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1584                 permutation |= SHADERPERMUTATION_ALPHAKILL;
1585         if (t->currentmaterialflags & MATERIALFLAG_OCCLUDE)
1586                 permutation |= SHADERPERMUTATION_OCCLUDE;
1587         if (t->r_water_waterscroll[0] && t->r_water_waterscroll[1])
1588                 permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
1589         if (rsurfacepass == RSURFPASS_BACKGROUND)
1590         {
1591                 // distorted background
1592                 if (t->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1593                 {
1594                         mode = SHADERMODE_WATER;
1595                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1596                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1597                         if((r_wateralpha.value < 1) && (t->currentmaterialflags & MATERIALFLAG_WATERALPHA))
1598                         {
1599                                 // this is the right thing to do for wateralpha
1600                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1601                                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1602                         }
1603                         else
1604                         {
1605                                 // this is the right thing to do for entity alpha
1606                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1607                                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1608                         }
1609                 }
1610                 else if (t->currentmaterialflags & MATERIALFLAG_REFRACTION)
1611                 {
1612                         mode = SHADERMODE_REFRACTION;
1613                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1614                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1615                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1616                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1617                 }
1618                 else
1619                 {
1620                         mode = SHADERMODE_GENERIC;
1621                         permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL;
1622                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1623                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1624                 }
1625                 if (vid.allowalphatocoverage)
1626                         GL_AlphaToCoverage(false);
1627         }
1628         else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
1629         {
1630                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1631                 {
1632                         switch(t->offsetmapping)
1633                         {
1634                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1635                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1636                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1637                         case OFFSETMAPPING_OFF: break;
1638                         }
1639                 }
1640                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1641                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1642                 // normalmap (deferred prepass), may use alpha test on diffuse
1643                 mode = SHADERMODE_DEFERREDGEOMETRY;
1644                 GL_BlendFunc(GL_ONE, GL_ZERO);
1645                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1646                 if (vid.allowalphatocoverage)
1647                         GL_AlphaToCoverage(false);
1648         }
1649         else if (rsurfacepass == RSURFPASS_RTLIGHT)
1650         {
1651                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1652                 {
1653                         switch(t->offsetmapping)
1654                         {
1655                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1656                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1657                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1658                         case OFFSETMAPPING_OFF: break;
1659                         }
1660                 }
1661                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1662                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1663                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1664                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1665                 // light source
1666                 mode = SHADERMODE_LIGHTSOURCE;
1667                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1668                         permutation |= SHADERPERMUTATION_CUBEFILTER;
1669                 if (VectorLength2(rtlightdiffuse) > 0)
1670                         permutation |= SHADERPERMUTATION_DIFFUSE;
1671                 if (VectorLength2(rtlightspecular) > 0)
1672                         permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1673                 if (r_refdef.fogenabled)
1674                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1675                 if (t->colormapping)
1676                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1677                 if (r_shadow_usingshadowmap2d)
1678                 {
1679                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1680                         if(r_shadow_shadowmapvsdct)
1681                                 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
1682
1683                         if (r_shadow_shadowmap2ddepthbuffer)
1684                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1685                 }
1686                 if (t->reflectmasktexture)
1687                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1688                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1689                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE);
1690                 if (vid.allowalphatocoverage)
1691                         GL_AlphaToCoverage(false);
1692         }
1693         else if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
1694         {
1695                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1696                 {
1697                         switch(t->offsetmapping)
1698                         {
1699                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1700                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1701                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1702                         case OFFSETMAPPING_OFF: break;
1703                         }
1704                 }
1705                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1706                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1707                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1708                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1709                 // directional model lighting
1710                 mode = SHADERMODE_LIGHTDIRECTION;
1711                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1712                         permutation |= SHADERPERMUTATION_GLOW;
1713                 if (VectorLength2(t->render_modellight_diffuse))
1714                         permutation |= SHADERPERMUTATION_DIFFUSE;
1715                 if (VectorLength2(t->render_modellight_specular) > 0)
1716                         permutation |= SHADERPERMUTATION_SPECULAR;
1717                 if (r_refdef.fogenabled)
1718                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1719                 if (t->colormapping)
1720                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1721                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1722                 {
1723                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1724                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1725
1726                         if (r_shadow_shadowmap2ddepthbuffer)
1727                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1728                 }
1729                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1730                         permutation |= SHADERPERMUTATION_REFLECTION;
1731                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1732                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1733                 if (t->reflectmasktexture)
1734                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1735                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1736                 {
1737                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1738                         if (r_shadow_bouncegrid_state.directional)
1739                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1740                 }
1741                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1742                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1743                 // when using alphatocoverage, we don't need alphakill
1744                 if (vid.allowalphatocoverage)
1745                 {
1746                         if (r_transparent_alphatocoverage.integer)
1747                         {
1748                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1749                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1750                         }
1751                         else
1752                                 GL_AlphaToCoverage(false);
1753                 }
1754         }
1755         else
1756         {
1757                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1758                 {
1759                         switch(t->offsetmapping)
1760                         {
1761                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1762                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1763                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1764                         case OFFSETMAPPING_OFF: break;
1765                         }
1766                 }
1767                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1768                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1769                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1770                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1771                 // lightmapped wall
1772                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1773                         permutation |= SHADERPERMUTATION_GLOW;
1774                 if (r_refdef.fogenabled)
1775                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1776                 if (t->colormapping)
1777                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1778                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1779                 {
1780                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1781                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1782
1783                         if (r_shadow_shadowmap2ddepthbuffer)
1784                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1785                 }
1786                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1787                         permutation |= SHADERPERMUTATION_REFLECTION;
1788                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1789                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1790                 if (t->reflectmasktexture)
1791                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1792                 if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
1793                 {
1794                         // deluxemapping (light direction texture)
1795                         if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace)
1796                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1797                         else
1798                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1799                         permutation |= SHADERPERMUTATION_DIFFUSE;
1800                         if (VectorLength2(t->render_lightmap_specular) > 0)
1801                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1802                 }
1803                 else if (r_glsl_deluxemapping.integer >= 2)
1804                 {
1805                         // fake deluxemapping (uniform light direction in tangentspace)
1806                         if (rsurface.uselightmaptexture)
1807                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP;
1808                         else
1809                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR;
1810                         permutation |= SHADERPERMUTATION_DIFFUSE;
1811                         if (VectorLength2(t->render_lightmap_specular) > 0)
1812                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1813                 }
1814                 else if (rsurface.uselightmaptexture)
1815                 {
1816                         // ordinary lightmapping (q1bsp, q3bsp)
1817                         mode = SHADERMODE_LIGHTMAP;
1818                 }
1819                 else
1820                 {
1821                         // ordinary vertex coloring (q3bsp)
1822                         mode = SHADERMODE_VERTEXCOLOR;
1823                 }
1824                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1825                 {
1826                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1827                         if (r_shadow_bouncegrid_state.directional)
1828                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1829                 }
1830                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1831                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1832                 // when using alphatocoverage, we don't need alphakill
1833                 if (vid.allowalphatocoverage)
1834                 {
1835                         if (r_transparent_alphatocoverage.integer)
1836                         {
1837                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1838                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1839                         }
1840                         else
1841                                 GL_AlphaToCoverage(false);
1842                 }
1843         }
1844         if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG))
1845                 permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE);
1846         if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1847                 permutation |= SHADERPERMUTATION_FOGALPHAHACK;
1848         switch(vid.renderpath)
1849         {
1850         case RENDERPATH_GL32:
1851         case RENDERPATH_GLES2:
1852                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | (rsurface.modellightmapcolor4f ? BATCHNEED_ARRAY_VERTEXCOLOR : 0) | BATCHNEED_ARRAY_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_ARRAY_LIGHTMAP : 0) | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
1853                 RSurf_UploadBuffersForBatch();
1854                 // this has to be after RSurf_PrepareVerticesForBatch
1855                 if (rsurface.batchskeletaltransform3x4buffer)
1856                         permutation |= SHADERPERMUTATION_SKELETAL;
1857                 R_SetupShader_SetPermutationGLSL(mode, permutation);
1858 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1859                 if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
1860 #endif
1861                 if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
1862                 if (mode == SHADERMODE_LIGHTSOURCE)
1863                 {
1864                         if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
1865                         if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1866                         if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1867                         if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
1868                         if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
1869                         if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
1870         
1871                         // additive passes are only darkened by fog, not tinted
1872                         if (r_glsl_permutation->loc_FogColor >= 0)
1873                                 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1874                         if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, t->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
1875                 }
1876                 else
1877                 {
1878                         if (mode == SHADERMODE_FLATCOLOR)
1879                         {
1880                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
1881                         }
1882                         else if (mode == SHADERMODE_LIGHTDIRECTION)
1883                         {
1884                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
1885                                 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_modellight_diffuse[0], t->render_modellight_diffuse[1], t->render_modellight_diffuse[2]);
1886                                 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_modellight_specular[0], t->render_modellight_specular[1], t->render_modellight_specular[2]);
1887                                 if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, t->render_rtlight_diffuse[0], t->render_rtlight_diffuse[1], t->render_rtlight_diffuse[2]);
1888                                 if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, t->render_rtlight_specular[0], t->render_rtlight_specular[1], t->render_rtlight_specular[2]);
1889                                 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1890                                 if (r_glsl_permutation->loc_LightDir >= 0) qglUniform3f(r_glsl_permutation->loc_LightDir, t->render_modellight_lightdir[0], t->render_modellight_lightdir[1], t->render_modellight_lightdir[2]);
1891                         }
1892                         else
1893                         {
1894                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_lightmap_ambient[0], t->render_lightmap_ambient[1], t->render_lightmap_ambient[2]);
1895                                 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_lightmap_diffuse[0], t->render_lightmap_diffuse[1], t->render_lightmap_diffuse[2]);
1896                                 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_lightmap_specular[0], t->render_lightmap_specular[1], t->render_lightmap_specular[2]);
1897                                 if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, t->render_rtlight_diffuse[0], t->render_rtlight_diffuse[1], t->render_rtlight_diffuse[2]);
1898                                 if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, t->render_rtlight_specular[0], t->render_rtlight_specular[1], t->render_rtlight_specular[2]);
1899                         }
1900                         // additive passes are only darkened by fog, not tinted
1901                         if (r_glsl_permutation->loc_FogColor >= 0)
1902                         {
1903                                 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
1904                                         qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1905                                 else
1906                                         qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1907                         }
1908                         if (r_glsl_permutation->loc_DistortScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_DistortScaleRefractReflect, r_water_refractdistort.value * t->refractfactor, r_water_refractdistort.value * t->refractfactor, r_water_reflectdistort.value * t->reflectfactor, r_water_reflectdistort.value * t->reflectfactor);
1909                         if (r_glsl_permutation->loc_ScreenScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenScaleRefractReflect, r_fb.water.screenscale[0], r_fb.water.screenscale[1], r_fb.water.screenscale[0], r_fb.water.screenscale[1]);
1910                         if (r_glsl_permutation->loc_ScreenCenterRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenCenterRefractReflect, r_fb.water.screencenter[0], r_fb.water.screencenter[1], r_fb.water.screencenter[0], r_fb.water.screencenter[1]);
1911                         if (r_glsl_permutation->loc_RefractColor >= 0) qglUniform4f(r_glsl_permutation->loc_RefractColor, t->refractcolor4f[0], t->refractcolor4f[1], t->refractcolor4f[2], t->refractcolor4f[3] * t->currentalpha);
1912                         if (r_glsl_permutation->loc_ReflectColor >= 0) qglUniform4f(r_glsl_permutation->loc_ReflectColor, t->reflectcolor4f[0], t->reflectcolor4f[1], t->reflectcolor4f[2], t->reflectcolor4f[3] * t->currentalpha);
1913                         if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, t->reflectmax - t->reflectmin);
1914                         if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, t->reflectmin);
1915                         if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, t->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
1916                         if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
1917                 }
1918                 if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
1919                 if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
1920                 if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
1921                 if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
1922                 {
1923                         if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_modelshadowmap_texturescale[0], r_shadow_modelshadowmap_texturescale[1], r_shadow_modelshadowmap_texturescale[2], r_shadow_modelshadowmap_texturescale[3]);
1924                         if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_modelshadowmap_parameters[0], r_shadow_modelshadowmap_parameters[1], r_shadow_modelshadowmap_parameters[2], r_shadow_modelshadowmap_parameters[3]);
1925                 }
1926                 else
1927                 {
1928                         if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
1929                         if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
1930                 }
1931
1932                 if (r_glsl_permutation->loc_Color_Glow >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Glow, t->render_glowmod[0], t->render_glowmod[1], t->render_glowmod[2]);
1933                 if (r_glsl_permutation->loc_Alpha >= 0) qglUniform1f(r_glsl_permutation->loc_Alpha, t->currentalpha * ((t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? t->r_water_wateralpha : 1));
1934                 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
1935                 if (r_glsl_permutation->loc_Color_Pants >= 0)
1936                 {
1937                         if (t->pantstexture)
1938                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
1939                         else
1940                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
1941                 }
1942                 if (r_glsl_permutation->loc_Color_Shirt >= 0)
1943                 {
1944                         if (t->shirttexture)
1945                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
1946                         else
1947                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
1948                 }
1949                 if (r_glsl_permutation->loc_FogPlane >= 0) qglUniform4f(r_glsl_permutation->loc_FogPlane, rsurface.fogplane[0], rsurface.fogplane[1], rsurface.fogplane[2], rsurface.fogplane[3]);
1950                 if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
1951                 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
1952                 if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
1953                 if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps,
1954                                 r_glsl_offsetmapping_scale.value*t->offsetscale,
1955                                 max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
1956                                 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
1957                                 max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
1958                         );
1959                 if (r_glsl_permutation->loc_OffsetMapping_LodDistance >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer * r_refdef.view.quality);
1960                 if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, t->offsetbias);
1961                 if (r_glsl_permutation->loc_ScreenToDepth >= 0) qglUniform2f(r_glsl_permutation->loc_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
1962                 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
1963                 if (r_glsl_permutation->loc_BounceGridMatrix >= 0) {Matrix4x4_Concat(&tempmatrix, &r_shadow_bouncegrid_state.matrix, &rsurface.matrix);Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BounceGridMatrix, 1, false, m16f);}
1964                 if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
1965
1966                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First            , r_texture_white                                     );
1967                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second           , r_texture_white                                     );
1968                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps       , r_texture_gammaramps                                );
1969                 if (r_glsl_permutation->tex_Texture_Normal          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal           , t->nmaptexture                       );
1970                 if (r_glsl_permutation->tex_Texture_Color           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color            , t->basetexture                       );
1971                 if (r_glsl_permutation->tex_Texture_Gloss           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss            , t->glosstexture                      );
1972                 if (r_glsl_permutation->tex_Texture_Glow            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow             , t->glowtexture                       );
1973                 if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal  , t->backgroundnmaptexture             );
1974                 if (r_glsl_permutation->tex_Texture_SecondaryColor  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor   , t->backgroundbasetexture             );
1975                 if (r_glsl_permutation->tex_Texture_SecondaryGloss  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss   , t->backgroundglosstexture            );
1976                 if (r_glsl_permutation->tex_Texture_SecondaryGlow   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow    , t->backgroundglowtexture             );
1977                 if (r_glsl_permutation->tex_Texture_Pants           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants            , t->pantstexture                      );
1978                 if (r_glsl_permutation->tex_Texture_Shirt           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt            , t->shirttexture                      );
1979                 if (r_glsl_permutation->tex_Texture_ReflectMask     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask      , t->reflectmasktexture                );
1980                 if (r_glsl_permutation->tex_Texture_ReflectCube     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube      , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
1981                 if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture                          );
1982                 if (r_glsl_permutation->tex_Texture_FogMask         >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask          , r_texture_fogattenuation                            );
1983                 if (r_glsl_permutation->tex_Texture_Lightmap        >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap         , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
1984                 if (r_glsl_permutation->tex_Texture_Deluxemap       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Deluxemap        , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap);
1985                 if (r_glsl_permutation->tex_Texture_Attenuation     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation      , r_shadow_attenuationgradienttexture                 );
1986                 if (rsurfacepass == RSURFPASS_BACKGROUND)
1987                 {
1988                         if (r_glsl_permutation->tex_Texture_Refraction  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Refraction        , waterplane->rt_refraction ? waterplane->rt_refraction->colortexture[0] : r_texture_black);
1989                         if (r_glsl_permutation->tex_Texture_First       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First             , waterplane->rt_camera ? waterplane->rt_camera->colortexture[0] : r_texture_black);
1990                         if (r_glsl_permutation->tex_Texture_Reflection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection        , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
1991                 }
1992                 else
1993                 {
1994                         if (r_glsl_permutation->tex_Texture_Reflection >= 0 && waterplane) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection        , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
1995                 }
1996                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap   , r_shadow_prepassgeometrynormalmaptexture            );
1997                 if (r_glsl_permutation->tex_Texture_ScreenDiffuse   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse     , r_shadow_prepasslightingdiffusetexture              );
1998                 if (r_glsl_permutation->tex_Texture_ScreenSpecular  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular    , r_shadow_prepasslightingspeculartexture             );
1999                 if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
2000                 {
2001                         if (r_glsl_permutation->tex_Texture_ShadowMap2D     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture                           );
2002                         if (rsurface.rtlight)
2003                         {
2004                                 if (r_glsl_permutation->tex_Texture_Cube            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube              , rsurface.rtlight->currentcubemap                    );
2005                                 if (r_glsl_permutation->tex_Texture_CubeProjection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection    , r_shadow_shadowmapvsdcttexture                      );
2006                         }
2007                 }
2008                 if (r_glsl_permutation->tex_Texture_BounceGrid  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
2009                 CHECKGLERROR
2010                 break;
2011         }
2012 }
2013
2014 void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
2015 {
2016         // select a permutation of the lighting shader appropriate to this
2017         // combination of texture, entity, light source, and fogging, only use the
2018         // minimum features necessary to avoid wasting rendering time in the
2019         // fragment shader on features that are not being used
2020         dpuint64 permutation = 0;
2021         unsigned int mode = 0;
2022         const float *lightcolorbase = rtlight->currentcolor;
2023         float ambientscale = rtlight->ambientscale;
2024         float diffusescale = rtlight->diffusescale;
2025         float specularscale = rtlight->specularscale;
2026         // this is the location of the light in view space
2027         vec3_t viewlightorigin;
2028         // this transforms from view space (camera) to light space (cubemap)
2029         matrix4x4_t viewtolight;
2030         matrix4x4_t lighttoview;
2031         float viewtolight16f[16];
2032         // light source
2033         mode = SHADERMODE_DEFERREDLIGHTSOURCE;
2034         if (rtlight->currentcubemap != r_texture_whitecube)
2035                 permutation |= SHADERPERMUTATION_CUBEFILTER;
2036         if (diffusescale > 0)
2037                 permutation |= SHADERPERMUTATION_DIFFUSE;
2038         if (specularscale > 0 && r_shadow_gloss.integer > 0)
2039                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2040         if (r_shadow_usingshadowmap2d)
2041         {
2042                 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
2043                 if (r_shadow_shadowmapvsdct)
2044                         permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
2045
2046                 if (r_shadow_shadowmap2ddepthbuffer)
2047                         permutation |= SHADERPERMUTATION_DEPTHRGB;
2048         }
2049         if (vid.allowalphatocoverage)
2050                 GL_AlphaToCoverage(false);
2051         Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
2052         Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
2053         Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
2054         Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
2055         switch(vid.renderpath)
2056         {
2057         case RENDERPATH_GL32:
2058         case RENDERPATH_GLES2:
2059                 R_SetupShader_SetPermutationGLSL(mode, permutation);
2060                 if (r_glsl_permutation->loc_LightPosition             >= 0) qglUniform3f(       r_glsl_permutation->loc_LightPosition            , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
2061                 if (r_glsl_permutation->loc_ViewToLight               >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight              , 1, false, viewtolight16f);
2062                 if (r_glsl_permutation->loc_DeferredColor_Ambient     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Ambient    , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
2063                 if (r_glsl_permutation->loc_DeferredColor_Diffuse     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
2064                 if (r_glsl_permutation->loc_DeferredColor_Specular    >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Specular   , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
2065                 if (r_glsl_permutation->loc_ShadowMap_TextureScale    >= 0) qglUniform4f(       r_glsl_permutation->loc_ShadowMap_TextureScale   , r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
2066                 if (r_glsl_permutation->loc_ShadowMap_Parameters      >= 0) qglUniform4f(       r_glsl_permutation->loc_ShadowMap_Parameters     , r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
2067                 if (r_glsl_permutation->loc_SpecularPower             >= 0) qglUniform1f(       r_glsl_permutation->loc_SpecularPower            , (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
2068                 if (r_glsl_permutation->loc_ScreenToDepth             >= 0) qglUniform2f(       r_glsl_permutation->loc_ScreenToDepth            , r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
2069                 if (r_glsl_permutation->loc_PixelToScreenTexCoord     >= 0) qglUniform2f(       r_glsl_permutation->loc_PixelToScreenTexCoord    , 1.0f/vid.width, 1.0f/vid.height);
2070
2071                 if (r_glsl_permutation->tex_Texture_Attenuation       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation        , r_shadow_attenuationgradienttexture                 );
2072                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap    , r_shadow_prepassgeometrynormalmaptexture            );
2073                 if (r_glsl_permutation->tex_Texture_Cube              >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube               , rsurface.rtlight->currentcubemap                    );
2074                 if (r_glsl_permutation->tex_Texture_ShadowMap2D       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D        , r_shadow_shadowmap2ddepthtexture                    );
2075                 if (r_glsl_permutation->tex_Texture_CubeProjection    >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection     , r_shadow_shadowmapvsdcttexture                      );
2076                 break;
2077         }
2078 }
2079
2080 #define SKINFRAME_HASH 1024
2081
2082 typedef struct
2083 {
2084         unsigned int loadsequence; // incremented each level change
2085         memexpandablearray_t array;
2086         skinframe_t *hash[SKINFRAME_HASH];
2087 }
2088 r_skinframe_t;
2089 r_skinframe_t r_skinframe;
2090
2091 void R_SkinFrame_PrepareForPurge(void)
2092 {
2093         r_skinframe.loadsequence++;
2094         // wrap it without hitting zero
2095         if (r_skinframe.loadsequence >= 200)
2096                 r_skinframe.loadsequence = 1;
2097 }
2098
2099 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
2100 {
2101         if (!skinframe)
2102                 return;
2103         // mark the skinframe as used for the purging code
2104         skinframe->loadsequence = r_skinframe.loadsequence;
2105 }
2106
2107 void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
2108 {
2109         if (s == NULL)
2110                 return;
2111         if (s->merged == s->base)
2112                 s->merged = NULL;
2113         R_PurgeTexture(s->stain); s->stain = NULL;
2114         R_PurgeTexture(s->merged); s->merged = NULL;
2115         R_PurgeTexture(s->base); s->base = NULL;
2116         R_PurgeTexture(s->pants); s->pants = NULL;
2117         R_PurgeTexture(s->shirt); s->shirt = NULL;
2118         R_PurgeTexture(s->nmap); s->nmap = NULL;
2119         R_PurgeTexture(s->gloss); s->gloss = NULL;
2120         R_PurgeTexture(s->glow); s->glow = NULL;
2121         R_PurgeTexture(s->fog); s->fog = NULL;
2122         R_PurgeTexture(s->reflect); s->reflect = NULL;
2123         s->loadsequence = 0;
2124 }
2125
2126 void R_SkinFrame_Purge(void)
2127 {
2128         int i;
2129         skinframe_t *s;
2130         for (i = 0;i < SKINFRAME_HASH;i++)
2131         {
2132                 for (s = r_skinframe.hash[i];s;s = s->next)
2133                 {
2134                         if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
2135                                 R_SkinFrame_PurgeSkinFrame(s);
2136                 }
2137         }
2138 }
2139
2140 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
2141         skinframe_t *item;
2142         char basename[MAX_QPATH];
2143
2144         Image_StripImageExtension(name, basename, sizeof(basename));
2145
2146         if( last == NULL ) {
2147                 int hashindex;
2148                 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2149                 item = r_skinframe.hash[hashindex];
2150         } else {
2151                 item = last->next;
2152         }
2153
2154         // linearly search through the hash bucket
2155         for( ; item ; item = item->next ) {
2156                 if( !strcmp( item->basename, basename ) ) {
2157                         return item;
2158                 }
2159         }
2160         return NULL;
2161 }
2162
2163 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add)
2164 {
2165         skinframe_t *item;
2166         int compareflags = textureflags & TEXF_IMPORTANTBITS;
2167         int hashindex;
2168         char basename[MAX_QPATH];
2169
2170         Image_StripImageExtension(name, basename, sizeof(basename));
2171
2172         hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2173         for (item = r_skinframe.hash[hashindex];item;item = item->next)
2174                 if (!strcmp(item->basename, basename) &&
2175                         item->textureflags == compareflags &&
2176                         item->comparewidth == comparewidth &&
2177                         item->compareheight == compareheight &&
2178                         item->comparecrc == comparecrc)
2179                         break;
2180
2181         if (!item)
2182         {
2183                 if (!add)
2184                         return NULL;
2185                 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
2186                 memset(item, 0, sizeof(*item));
2187                 strlcpy(item->basename, basename, sizeof(item->basename));
2188                 item->textureflags = compareflags;
2189                 item->comparewidth = comparewidth;
2190                 item->compareheight = compareheight;
2191                 item->comparecrc = comparecrc;
2192                 item->next = r_skinframe.hash[hashindex];
2193                 r_skinframe.hash[hashindex] = item;
2194         }
2195         else if (textureflags & TEXF_FORCE_RELOAD)
2196                 R_SkinFrame_PurgeSkinFrame(item);
2197
2198         R_SkinFrame_MarkUsed(item);
2199         return item;
2200 }
2201
2202 #define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
2203         { \
2204                 unsigned long long avgcolor[5], wsum; \
2205                 int pix, comp, w; \
2206                 avgcolor[0] = 0; \
2207                 avgcolor[1] = 0; \
2208                 avgcolor[2] = 0; \
2209                 avgcolor[3] = 0; \
2210                 avgcolor[4] = 0; \
2211                 wsum = 0; \
2212                 for(pix = 0; pix < cnt; ++pix) \
2213                 { \
2214                         w = 0; \
2215                         for(comp = 0; comp < 3; ++comp) \
2216                                 w += getpixel; \
2217                         if(w) /* ignore perfectly black pixels because that is better for model skins */ \
2218                         { \
2219                                 ++wsum; \
2220                                 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2221                                 w = getpixel; \
2222                                 for(comp = 0; comp < 3; ++comp) \
2223                                         avgcolor[comp] += getpixel * w; \
2224                                 avgcolor[3] += w; \
2225                         } \
2226                         /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2227                         avgcolor[4] += getpixel; \
2228                 } \
2229                 if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
2230                         avgcolor[3] = 1; \
2231                 skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
2232                 skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
2233                 skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
2234                 skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
2235         }
2236
2237 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2238 {
2239         skinframe_t *skinframe;
2240
2241         if (cls.state == ca_dedicated)
2242                 return NULL;
2243
2244         // return an existing skinframe if already loaded
2245         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
2246         if (skinframe && skinframe->base)
2247                 return skinframe;
2248
2249         // if the skinframe doesn't exist this will create it
2250         return R_SkinFrame_LoadExternal_SkinFrame(skinframe, name, textureflags, complain, fallbacknotexture);
2251 }
2252
2253 extern cvar_t gl_picmip;
2254 skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2255 {
2256         int j;
2257         unsigned char *pixels;
2258         unsigned char *bumppixels;
2259         unsigned char *basepixels = NULL;
2260         int basepixels_width = 0;
2261         int basepixels_height = 0;
2262         rtexture_t *ddsbase = NULL;
2263         qboolean ddshasalpha = false;
2264         float ddsavgcolor[4];
2265         char basename[MAX_QPATH];
2266         int miplevel = R_PicmipForFlags(textureflags);
2267         int savemiplevel = miplevel;
2268         int mymiplevel;
2269         char vabuf[1024];
2270
2271         if (cls.state == ca_dedicated)
2272                 return NULL;
2273
2274         Image_StripImageExtension(name, basename, sizeof(basename));
2275
2276         // check for DDS texture file first
2277         if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2278         {
2279                 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2280                 if (basepixels == NULL && fallbacknotexture)
2281                         basepixels = Image_GenerateNoTexture();
2282                 if (basepixels == NULL)
2283                         return NULL;
2284         }
2285
2286         // FIXME handle miplevel
2287
2288         if (developer_loading.integer)
2289                 Con_Printf("loading skin \"%s\"\n", name);
2290
2291         // we've got some pixels to store, so really allocate this new texture now
2292         if (!skinframe)
2293                 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2294         textureflags &= ~TEXF_FORCE_RELOAD;
2295         skinframe->stain = NULL;
2296         skinframe->merged = NULL;
2297         skinframe->base = NULL;
2298         skinframe->pants = NULL;
2299         skinframe->shirt = NULL;
2300         skinframe->nmap = NULL;
2301         skinframe->gloss = NULL;
2302         skinframe->glow = NULL;
2303         skinframe->fog = NULL;
2304         skinframe->reflect = NULL;
2305         skinframe->hasalpha = false;
2306         // we could store the q2animname here too
2307
2308         if (ddsbase)
2309         {
2310                 skinframe->base = ddsbase;
2311                 skinframe->hasalpha = ddshasalpha;
2312                 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2313                 if (r_loadfog && skinframe->hasalpha)
2314                         skinframe->fog = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), false, textureflags | TEXF_ALPHA, NULL, NULL, miplevel, true);
2315                 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2316         }
2317         else
2318         {
2319                 basepixels_width = image_width;
2320                 basepixels_height = image_height;
2321                 skinframe->base = R_LoadTexture2D (r_main_texturepool, skinframe->basename, basepixels_width, basepixels_height, basepixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL);
2322                 if (textureflags & TEXF_ALPHA)
2323                 {
2324                         for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2325                         {
2326                                 if (basepixels[j] < 255)
2327                                 {
2328                                         skinframe->hasalpha = true;
2329                                         break;
2330                                 }
2331                         }
2332                         if (r_loadfog && skinframe->hasalpha)
2333                         {
2334                                 // has transparent pixels
2335                                 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2336                                 for (j = 0;j < image_width * image_height * 4;j += 4)
2337                                 {
2338                                         pixels[j+0] = 255;
2339                                         pixels[j+1] = 255;
2340                                         pixels[j+2] = 255;
2341                                         pixels[j+3] = basepixels[j+3];
2342                                 }
2343                                 skinframe->fog = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_mask", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL);
2344                                 Mem_Free(pixels);
2345                         }
2346                 }
2347                 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2348 #ifndef USE_GLES2
2349                 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2350                 if (r_savedds && skinframe->base)
2351                         R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2352                 if (r_savedds && skinframe->fog)
2353                         R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2354 #endif
2355         }
2356
2357         if (r_loaddds)
2358         {
2359                 mymiplevel = savemiplevel;
2360                 if (r_loadnormalmap)
2361                         skinframe->nmap = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), false, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), NULL, NULL, mymiplevel, true);
2362                 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2363                 if (r_loadgloss)
2364                         skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2365                 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2366                 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2367                 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2368         }
2369
2370         // _norm is the name used by tenebrae and has been adopted as standard
2371         if (r_loadnormalmap && skinframe->nmap == NULL)
2372         {
2373                 mymiplevel = savemiplevel;
2374                 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2375                 {
2376                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2377                         Mem_Free(pixels);
2378                         pixels = NULL;
2379                 }
2380                 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2381                 {
2382                         pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2383                         Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2384                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2385                         Mem_Free(pixels);
2386                         Mem_Free(bumppixels);
2387                 }
2388                 else if (r_shadow_bumpscale_basetexture.value > 0)
2389                 {
2390                         pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2391                         Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2392                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), basepixels_width, basepixels_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2393                         Mem_Free(pixels);
2394                 }
2395 #ifndef USE_GLES2
2396                 if (r_savedds && skinframe->nmap)
2397                         R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2398 #endif
2399         }
2400
2401         // _luma is supported only for tenebrae compatibility
2402         // _blend and .blend are supported only for Q3 & QL compatibility, this hack can be removed if better Q3 shader support is implemented
2403         // _glow is the preferred name
2404         mymiplevel = savemiplevel;
2405         if (skinframe->glow == NULL && ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s.blend", skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_blend", skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_luma", skinframe->basename), false, false, false, &mymiplevel))))
2406         {
2407                 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);
2408 #ifndef USE_GLES2
2409                 if (r_savedds && skinframe->glow)
2410                         R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2411 #endif
2412                 Mem_Free(pixels);pixels = NULL;
2413         }
2414
2415         mymiplevel = savemiplevel;
2416         if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2417         {
2418                 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);
2419 #ifndef USE_GLES2
2420                 if (r_savedds && skinframe->gloss)
2421                         R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2422 #endif
2423                 Mem_Free(pixels);
2424                 pixels = NULL;
2425         }
2426
2427         mymiplevel = savemiplevel;
2428         if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2429         {
2430                 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);
2431 #ifndef USE_GLES2
2432                 if (r_savedds && skinframe->pants)
2433                         R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2434 #endif
2435                 Mem_Free(pixels);
2436                 pixels = NULL;
2437         }
2438
2439         mymiplevel = savemiplevel;
2440         if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2441         {
2442                 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);
2443 #ifndef USE_GLES2
2444                 if (r_savedds && skinframe->shirt)
2445                         R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2446 #endif
2447                 Mem_Free(pixels);
2448                 pixels = NULL;
2449         }
2450
2451         mymiplevel = savemiplevel;
2452         if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2453         {
2454                 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);
2455 #ifndef USE_GLES2
2456                 if (r_savedds && skinframe->reflect)
2457                         R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2458 #endif
2459                 Mem_Free(pixels);
2460                 pixels = NULL;
2461         }
2462
2463         if (basepixels)
2464                 Mem_Free(basepixels);
2465
2466         return skinframe;
2467 }
2468
2469 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)
2470 {
2471         int i;
2472         skinframe_t *skinframe;
2473         char vabuf[1024];
2474
2475         if (cls.state == ca_dedicated)
2476                 return NULL;
2477
2478         // if already loaded just return it, otherwise make a new skinframe
2479         skinframe = R_SkinFrame_Find(name, textureflags, comparewidth, compareheight, comparecrc, true);
2480         if (skinframe->base)
2481                 return skinframe;
2482         textureflags &= ~TEXF_FORCE_RELOAD;
2483
2484         skinframe->stain = NULL;
2485         skinframe->merged = NULL;
2486         skinframe->base = NULL;
2487         skinframe->pants = NULL;
2488         skinframe->shirt = NULL;
2489         skinframe->nmap = NULL;
2490         skinframe->gloss = NULL;
2491         skinframe->glow = NULL;
2492         skinframe->fog = NULL;
2493         skinframe->reflect = NULL;
2494         skinframe->hasalpha = false;
2495
2496         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2497         if (!skindata)
2498                 return NULL;
2499
2500         if (developer_loading.integer)
2501                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2502
2503         if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2504         {
2505                 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2506                 unsigned char *b = a + width * height * 4;
2507                 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2508                 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);
2509                 Mem_Free(a);
2510         }
2511         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2512         if (textureflags & TEXF_ALPHA)
2513         {
2514                 for (i = 3;i < width * height * 4;i += 4)
2515                 {
2516                         if (skindata[i] < 255)
2517                         {
2518                                 skinframe->hasalpha = true;
2519                                 break;
2520                         }
2521                 }
2522                 if (r_loadfog && skinframe->hasalpha)
2523                 {
2524                         unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2525                         memcpy(fogpixels, skindata, width * height * 4);
2526                         for (i = 0;i < width * height * 4;i += 4)
2527                                 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2528                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2529                         Mem_Free(fogpixels);
2530                 }
2531         }
2532
2533         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2534         //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]);
2535
2536         return skinframe;
2537 }
2538
2539 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2540 {
2541         int i;
2542         int featuresmask;
2543         skinframe_t *skinframe;
2544
2545         if (cls.state == ca_dedicated)
2546                 return NULL;
2547
2548         // if already loaded just return it, otherwise make a new skinframe
2549         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2550         if (skinframe->base)
2551                 return skinframe;
2552         //textureflags &= ~TEXF_FORCE_RELOAD;
2553
2554         skinframe->stain = NULL;
2555         skinframe->merged = NULL;
2556         skinframe->base = NULL;
2557         skinframe->pants = NULL;
2558         skinframe->shirt = NULL;
2559         skinframe->nmap = NULL;
2560         skinframe->gloss = NULL;
2561         skinframe->glow = NULL;
2562         skinframe->fog = NULL;
2563         skinframe->reflect = NULL;
2564         skinframe->hasalpha = false;
2565
2566         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2567         if (!skindata)
2568                 return NULL;
2569
2570         if (developer_loading.integer)
2571                 Con_Printf("loading quake skin \"%s\"\n", name);
2572
2573         // 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)
2574         skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2575         memcpy(skinframe->qpixels, skindata, width*height);
2576         skinframe->qwidth = width;
2577         skinframe->qheight = height;
2578
2579         featuresmask = 0;
2580         for (i = 0;i < width * height;i++)
2581                 featuresmask |= palette_featureflags[skindata[i]];
2582
2583         skinframe->hasalpha = false;
2584         // fence textures
2585         if (name[0] == '{')
2586                 skinframe->hasalpha = true;
2587         skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2588         skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2589         skinframe->qgeneratemerged = true;
2590         skinframe->qgeneratebase = skinframe->qhascolormapping;
2591         skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2592
2593         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2594         //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]);
2595
2596         return skinframe;
2597 }
2598
2599 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboolean colormapped)
2600 {
2601         int width;
2602         int height;
2603         unsigned char *skindata;
2604         char vabuf[1024];
2605
2606         if (!skinframe->qpixels)
2607                 return;
2608
2609         if (!skinframe->qhascolormapping)
2610                 colormapped = false;
2611
2612         if (colormapped)
2613         {
2614                 if (!skinframe->qgeneratebase)
2615                         return;
2616         }
2617         else
2618         {
2619                 if (!skinframe->qgeneratemerged)
2620                         return;
2621         }
2622
2623         width = skinframe->qwidth;
2624         height = skinframe->qheight;
2625         skindata = skinframe->qpixels;
2626
2627         if (skinframe->qgeneratenmap)
2628         {
2629                 unsigned char *a, *b;
2630                 skinframe->qgeneratenmap = false;
2631                 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2632                 b = a + width * height * 4;
2633                 // use either a custom palette or the quake palette
2634                 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2635                 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2636                 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);
2637                 Mem_Free(a);
2638         }
2639
2640         if (skinframe->qgenerateglow)
2641         {
2642                 skinframe->qgenerateglow = false;
2643                 if (skinframe->hasalpha) // fence textures
2644                         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
2645                 else
2646                         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
2647         }
2648
2649         if (colormapped)
2650         {
2651                 skinframe->qgeneratebase = false;
2652                 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);
2653                 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);
2654                 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);
2655         }
2656         else
2657         {
2658                 skinframe->qgeneratemerged = false;
2659                 if (skinframe->hasalpha) // fence textures
2660                         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);
2661                 else
2662                         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);
2663         }
2664
2665         if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2666         {
2667                 Mem_Free(skinframe->qpixels);
2668                 skinframe->qpixels = NULL;
2669         }
2670 }
2671
2672 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)
2673 {
2674         int i;
2675         skinframe_t *skinframe;
2676         char vabuf[1024];
2677
2678         if (cls.state == ca_dedicated)
2679                 return NULL;
2680
2681         // if already loaded just return it, otherwise make a new skinframe
2682         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2683         if (skinframe->base)
2684                 return skinframe;
2685         textureflags &= ~TEXF_FORCE_RELOAD;
2686
2687         skinframe->stain = NULL;
2688         skinframe->merged = NULL;
2689         skinframe->base = NULL;
2690         skinframe->pants = NULL;
2691         skinframe->shirt = NULL;
2692         skinframe->nmap = NULL;
2693         skinframe->gloss = NULL;
2694         skinframe->glow = NULL;
2695         skinframe->fog = NULL;
2696         skinframe->reflect = NULL;
2697         skinframe->hasalpha = false;
2698
2699         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2700         if (!skindata)
2701                 return NULL;
2702
2703         if (developer_loading.integer)
2704                 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2705
2706         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2707         if ((textureflags & TEXF_ALPHA) && alphapalette)
2708         {
2709                 for (i = 0;i < width * height;i++)
2710                 {
2711                         if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2712                         {
2713                                 skinframe->hasalpha = true;
2714                                 break;
2715                         }
2716                 }
2717                 if (r_loadfog && skinframe->hasalpha)
2718                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2719         }
2720
2721         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2722         //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]);
2723
2724         return skinframe;
2725 }
2726
2727 skinframe_t *R_SkinFrame_LoadMissing(void)
2728 {
2729         skinframe_t *skinframe;
2730
2731         if (cls.state == ca_dedicated)
2732                 return NULL;
2733
2734         skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2735         skinframe->stain = NULL;
2736         skinframe->merged = NULL;
2737         skinframe->base = NULL;
2738         skinframe->pants = NULL;
2739         skinframe->shirt = NULL;
2740         skinframe->nmap = NULL;
2741         skinframe->gloss = NULL;
2742         skinframe->glow = NULL;
2743         skinframe->fog = NULL;
2744         skinframe->reflect = NULL;
2745         skinframe->hasalpha = false;
2746
2747         skinframe->avgcolor[0] = rand() / RAND_MAX;
2748         skinframe->avgcolor[1] = rand() / RAND_MAX;
2749         skinframe->avgcolor[2] = rand() / RAND_MAX;
2750         skinframe->avgcolor[3] = 1;
2751
2752         return skinframe;
2753 }
2754
2755 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2756 {
2757         int x, y;
2758         static unsigned char pix[16][16][4];
2759
2760         if (cls.state == ca_dedicated)
2761                 return NULL;
2762
2763         // this makes a light grey/dark grey checkerboard texture
2764         if (!pix[0][0][3])
2765         {
2766                 for (y = 0; y < 16; y++)
2767                 {
2768                         for (x = 0; x < 16; x++)
2769                         {
2770                                 if ((y < 8) ^ (x < 8))
2771                                 {
2772                                         pix[y][x][0] = 128;
2773                                         pix[y][x][1] = 128;
2774                                         pix[y][x][2] = 128;
2775                                         pix[y][x][3] = 255;
2776                                 }
2777                                 else
2778                                 {
2779                                         pix[y][x][0] = 64;
2780                                         pix[y][x][1] = 64;
2781                                         pix[y][x][2] = 64;
2782                                         pix[y][x][3] = 255;
2783                                 }
2784                         }
2785                 }
2786         }
2787
2788         return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, pix[0][0], 16, 16, 0, 0, 0, false);
2789 }
2790
2791 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qboolean sRGB)
2792 {
2793         skinframe_t *skinframe;
2794         if (cls.state == ca_dedicated)
2795                 return NULL;
2796         // if already loaded just return it, otherwise make a new skinframe
2797         skinframe = R_SkinFrame_Find(name, textureflags, width, height, 0, true);
2798         if (skinframe->base)
2799                 return skinframe;
2800         textureflags &= ~TEXF_FORCE_RELOAD;
2801         skinframe->stain = NULL;
2802         skinframe->merged = NULL;
2803         skinframe->base = NULL;
2804         skinframe->pants = NULL;
2805         skinframe->shirt = NULL;
2806         skinframe->nmap = NULL;
2807         skinframe->gloss = NULL;
2808         skinframe->glow = NULL;
2809         skinframe->fog = NULL;
2810         skinframe->reflect = NULL;
2811         skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2812         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2813         if (!tex)
2814                 return NULL;
2815         if (developer_loading.integer)
2816                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2817         skinframe->base = skinframe->merged = tex;
2818         Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2819         return skinframe;
2820 }
2821
2822 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2823 typedef struct suffixinfo_s
2824 {
2825         const char *suffix;
2826         qboolean flipx, flipy, flipdiagonal;
2827 }
2828 suffixinfo_t;
2829 static suffixinfo_t suffix[3][6] =
2830 {
2831         {
2832                 {"px",   false, false, false},
2833                 {"nx",   false, false, false},
2834                 {"py",   false, false, false},
2835                 {"ny",   false, false, false},
2836                 {"pz",   false, false, false},
2837                 {"nz",   false, false, false}
2838         },
2839         {
2840                 {"posx", false, false, false},
2841                 {"negx", false, false, false},
2842                 {"posy", false, false, false},
2843                 {"negy", false, false, false},
2844                 {"posz", false, false, false},
2845                 {"negz", false, false, false}
2846         },
2847         {
2848                 {"rt",    true, false,  true},
2849                 {"lf",   false,  true,  true},
2850                 {"ft",    true,  true, false},
2851                 {"bk",   false, false, false},
2852                 {"up",    true, false,  true},
2853                 {"dn",    true, false,  true}
2854         }
2855 };
2856
2857 static int componentorder[4] = {0, 1, 2, 3};
2858
2859 static rtexture_t *R_LoadCubemap(const char *basename)
2860 {
2861         int i, j, cubemapsize;
2862         unsigned char *cubemappixels, *image_buffer;
2863         rtexture_t *cubemaptexture;
2864         char name[256];
2865         // must start 0 so the first loadimagepixels has no requested width/height
2866         cubemapsize = 0;
2867         cubemappixels = NULL;
2868         cubemaptexture = NULL;
2869         // keep trying different suffix groups (posx, px, rt) until one loads
2870         for (j = 0;j < 3 && !cubemappixels;j++)
2871         {
2872                 // load the 6 images in the suffix group
2873                 for (i = 0;i < 6;i++)
2874                 {
2875                         // generate an image name based on the base and and suffix
2876                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2877                         // load it
2878                         if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
2879                         {
2880                                 // an image loaded, make sure width and height are equal
2881                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
2882                                 {
2883                                         // if this is the first image to load successfully, allocate the cubemap memory
2884                                         if (!cubemappixels && image_width >= 1)
2885                                         {
2886                                                 cubemapsize = image_width;
2887                                                 // note this clears to black, so unavailable sides are black
2888                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2889                                         }
2890                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2891                                         if (cubemappixels)
2892                                                 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);
2893                                 }
2894                                 else
2895                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2896                                 // free the image
2897                                 Mem_Free(image_buffer);
2898                         }
2899                 }
2900         }
2901         // if a cubemap loaded, upload it
2902         if (cubemappixels)
2903         {
2904                 if (developer_loading.integer)
2905                         Con_Printf("loading cubemap \"%s\"\n", basename);
2906
2907                 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);
2908                 Mem_Free(cubemappixels);
2909         }
2910         else
2911         {
2912                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
2913                 if (developer_loading.integer)
2914                 {
2915                         Con_Printf("(tried tried images ");
2916                         for (j = 0;j < 3;j++)
2917                                 for (i = 0;i < 6;i++)
2918                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2919                         Con_Print(" and was unable to find any of them).\n");
2920                 }
2921         }
2922         return cubemaptexture;
2923 }
2924
2925 rtexture_t *R_GetCubemap(const char *basename)
2926 {
2927         int i;
2928         for (i = 0;i < r_texture_numcubemaps;i++)
2929                 if (r_texture_cubemaps[i] != NULL)
2930                         if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
2931                                 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
2932         if (i >= MAX_CUBEMAPS || !r_main_mempool)
2933                 return r_texture_whitecube;
2934         r_texture_numcubemaps++;
2935         r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
2936         strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
2937         r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
2938         return r_texture_cubemaps[i]->texture;
2939 }
2940
2941 static void R_Main_FreeViewCache(void)
2942 {
2943         if (r_refdef.viewcache.entityvisible)
2944                 Mem_Free(r_refdef.viewcache.entityvisible);
2945         if (r_refdef.viewcache.world_pvsbits)
2946                 Mem_Free(r_refdef.viewcache.world_pvsbits);
2947         if (r_refdef.viewcache.world_leafvisible)
2948                 Mem_Free(r_refdef.viewcache.world_leafvisible);
2949         if (r_refdef.viewcache.world_surfacevisible)
2950                 Mem_Free(r_refdef.viewcache.world_surfacevisible);
2951         memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
2952 }
2953
2954 static void R_Main_ResizeViewCache(void)
2955 {
2956         int numentities = r_refdef.scene.numentities;
2957         int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
2958         int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
2959         int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
2960         int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
2961         if (r_refdef.viewcache.maxentities < numentities)
2962         {
2963                 r_refdef.viewcache.maxentities = numentities;
2964                 if (r_refdef.viewcache.entityvisible)
2965                         Mem_Free(r_refdef.viewcache.entityvisible);
2966                 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
2967         }
2968         if (r_refdef.viewcache.world_numclusters != numclusters)
2969         {
2970                 r_refdef.viewcache.world_numclusters = numclusters;
2971                 r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
2972                 if (r_refdef.viewcache.world_pvsbits)
2973                         Mem_Free(r_refdef.viewcache.world_pvsbits);
2974                 r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
2975         }
2976         if (r_refdef.viewcache.world_numleafs != numleafs)
2977         {
2978                 r_refdef.viewcache.world_numleafs = numleafs;
2979                 if (r_refdef.viewcache.world_leafvisible)
2980                         Mem_Free(r_refdef.viewcache.world_leafvisible);
2981                 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
2982         }
2983         if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
2984         {
2985                 r_refdef.viewcache.world_numsurfaces = numsurfaces;
2986                 if (r_refdef.viewcache.world_surfacevisible)
2987                         Mem_Free(r_refdef.viewcache.world_surfacevisible);
2988                 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
2989         }
2990 }
2991
2992 extern rtexture_t *loadingscreentexture;
2993 static void gl_main_start(void)
2994 {
2995         loadingscreentexture = NULL;
2996         r_texture_blanknormalmap = NULL;
2997         r_texture_white = NULL;
2998         r_texture_grey128 = NULL;
2999         r_texture_black = NULL;
3000         r_texture_whitecube = NULL;
3001         r_texture_normalizationcube = NULL;
3002         r_texture_fogattenuation = NULL;
3003         r_texture_fogheighttexture = NULL;
3004         r_texture_gammaramps = NULL;
3005         r_texture_numcubemaps = 0;
3006         r_uniformbufferalignment = 32;
3007
3008         r_loaddds = r_texture_dds_load.integer != 0;
3009         r_savedds = vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3010
3011         switch(vid.renderpath)
3012         {
3013         case RENDERPATH_GL32:
3014         case RENDERPATH_GLES2:
3015                 Cvar_SetValueQuick(&r_textureunits, MAX_TEXTUREUNITS);
3016                 Cvar_SetValueQuick(&gl_combine, 1);
3017                 Cvar_SetValueQuick(&r_glsl, 1);
3018                 r_loadnormalmap = true;
3019                 r_loadgloss = true;
3020                 r_loadfog = false;
3021 #ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
3022                 qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
3023 #endif
3024                 break;
3025         }
3026
3027         R_AnimCache_Free();
3028         R_FrameData_Reset();
3029         R_BufferData_Reset();
3030
3031         r_numqueries = 0;
3032         r_maxqueries = 0;
3033         memset(r_queries, 0, sizeof(r_queries));
3034
3035         r_qwskincache = NULL;
3036         r_qwskincache_size = 0;
3037
3038         // due to caching of texture_t references, the collision cache must be reset
3039         Collision_Cache_Reset(true);
3040
3041         // set up r_skinframe loading system for textures
3042         memset(&r_skinframe, 0, sizeof(r_skinframe));
3043         r_skinframe.loadsequence = 1;
3044         Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
3045
3046         r_main_texturepool = R_AllocTexturePool();
3047         R_BuildBlankTextures();
3048         R_BuildNoTexture();
3049         R_BuildWhiteCube();
3050         R_BuildNormalizationCube();
3051         r_texture_fogattenuation = NULL;
3052         r_texture_fogheighttexture = NULL;
3053         r_texture_gammaramps = NULL;
3054         //r_texture_fogintensity = NULL;
3055         memset(&r_fb, 0, sizeof(r_fb));
3056         Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
3057         r_glsl_permutation = NULL;
3058         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3059         Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
3060         memset(&r_svbsp, 0, sizeof (r_svbsp));
3061
3062         memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
3063         r_texture_numcubemaps = 0;
3064
3065         r_refdef.fogmasktable_density = 0;
3066
3067 #ifdef __ANDROID__
3068         // For Steelstorm Android
3069         // FIXME CACHE the program and reload
3070         // FIXME see possible combinations for SS:BR android
3071         Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
3072         R_SetupShader_SetPermutationGLSL(0, 12);
3073         R_SetupShader_SetPermutationGLSL(0, 13);
3074         R_SetupShader_SetPermutationGLSL(0, 8388621);
3075         R_SetupShader_SetPermutationGLSL(3, 0);
3076         R_SetupShader_SetPermutationGLSL(3, 2048);
3077         R_SetupShader_SetPermutationGLSL(5, 0);
3078         R_SetupShader_SetPermutationGLSL(5, 2);
3079         R_SetupShader_SetPermutationGLSL(5, 2048);
3080         R_SetupShader_SetPermutationGLSL(5, 8388608);
3081         R_SetupShader_SetPermutationGLSL(11, 1);
3082         R_SetupShader_SetPermutationGLSL(11, 2049);
3083         R_SetupShader_SetPermutationGLSL(11, 8193);
3084         R_SetupShader_SetPermutationGLSL(11, 10241);
3085         Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
3086 #endif
3087 }
3088
3089 extern unsigned int r_shadow_occlusion_buf;
3090
3091 static void gl_main_shutdown(void)
3092 {
3093         R_RenderTarget_FreeUnused(true);
3094         Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
3095         R_AnimCache_Free();
3096         R_FrameData_Reset();
3097         R_BufferData_Reset();
3098
3099         R_Main_FreeViewCache();
3100
3101         switch(vid.renderpath)
3102         {
3103         case RENDERPATH_GL32:
3104         case RENDERPATH_GLES2:
3105 #if defined(GL_SAMPLES_PASSED) && !defined(USE_GLES2)
3106                 if (r_maxqueries)
3107                         qglDeleteQueries(r_maxqueries, r_queries);
3108 #endif
3109                 break;
3110         }
3111         r_shadow_occlusion_buf = 0;
3112         r_numqueries = 0;
3113         r_maxqueries = 0;
3114         memset(r_queries, 0, sizeof(r_queries));
3115
3116         r_qwskincache = NULL;
3117         r_qwskincache_size = 0;
3118
3119         // clear out the r_skinframe state
3120         Mem_ExpandableArray_FreeArray(&r_skinframe.array);
3121         memset(&r_skinframe, 0, sizeof(r_skinframe));
3122
3123         if (r_svbsp.nodes)
3124                 Mem_Free(r_svbsp.nodes);
3125         memset(&r_svbsp, 0, sizeof (r_svbsp));
3126         R_FreeTexturePool(&r_main_texturepool);
3127         loadingscreentexture = NULL;
3128         r_texture_blanknormalmap = NULL;
3129         r_texture_white = NULL;
3130         r_texture_grey128 = NULL;
3131         r_texture_black = NULL;
3132         r_texture_whitecube = NULL;
3133         r_texture_normalizationcube = NULL;
3134         r_texture_fogattenuation = NULL;
3135         r_texture_fogheighttexture = NULL;
3136         r_texture_gammaramps = NULL;
3137         r_texture_numcubemaps = 0;
3138         //r_texture_fogintensity = NULL;
3139         memset(&r_fb, 0, sizeof(r_fb));
3140         R_GLSL_Restart_f(&cmd_client);
3141
3142         r_glsl_permutation = NULL;
3143         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3144         Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
3145 }
3146
3147 static void gl_main_newmap(void)
3148 {
3149         // FIXME: move this code to client
3150         char *entities, entname[MAX_QPATH];
3151         if (r_qwskincache)
3152                 Mem_Free(r_qwskincache);
3153         r_qwskincache = NULL;
3154         r_qwskincache_size = 0;
3155         if (cl.worldmodel)
3156         {
3157                 dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension);
3158                 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
3159                 {
3160                         CL_ParseEntityLump(entities);
3161                         Mem_Free(entities);
3162                         return;
3163                 }
3164                 if (cl.worldmodel->brush.entities)
3165                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
3166         }
3167         R_Main_FreeViewCache();
3168
3169         R_FrameData_Reset();
3170         R_BufferData_Reset();
3171 }
3172
3173 void GL_Main_Init(void)
3174 {
3175         int i;
3176         r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
3177         R_InitShaderModeInfo();
3178
3179         Cmd_AddCommand(&cmd_client, "r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
3180         Cmd_AddCommand(&cmd_client, "r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
3181         // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
3182         if (gamemode == GAME_NEHAHRA)
3183         {
3184                 Cvar_RegisterVariable (&gl_fogenable);
3185                 Cvar_RegisterVariable (&gl_fogdensity);
3186                 Cvar_RegisterVariable (&gl_fogred);
3187                 Cvar_RegisterVariable (&gl_foggreen);
3188                 Cvar_RegisterVariable (&gl_fogblue);
3189                 Cvar_RegisterVariable (&gl_fogstart);
3190                 Cvar_RegisterVariable (&gl_fogend);
3191                 Cvar_RegisterVariable (&gl_skyclip);
3192         }
3193         Cvar_RegisterVariable(&r_motionblur);
3194         Cvar_RegisterVariable(&r_damageblur);
3195         Cvar_RegisterVariable(&r_motionblur_averaging);
3196         Cvar_RegisterVariable(&r_motionblur_randomize);
3197         Cvar_RegisterVariable(&r_motionblur_minblur);
3198         Cvar_RegisterVariable(&r_motionblur_maxblur);
3199         Cvar_RegisterVariable(&r_motionblur_velocityfactor);
3200         Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed);
3201         Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed);
3202         Cvar_RegisterVariable(&r_motionblur_mousefactor);
3203         Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed);
3204         Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed);
3205         Cvar_RegisterVariable(&r_depthfirst);
3206         Cvar_RegisterVariable(&r_useinfinitefarclip);
3207         Cvar_RegisterVariable(&r_farclip_base);
3208         Cvar_RegisterVariable(&r_farclip_world);
3209         Cvar_RegisterVariable(&r_nearclip);
3210         Cvar_RegisterVariable(&r_deformvertexes);
3211         Cvar_RegisterVariable(&r_transparent);
3212         Cvar_RegisterVariable(&r_transparent_alphatocoverage);
3213         Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
3214         Cvar_RegisterVariable(&r_transparent_useplanardistance);
3215         Cvar_RegisterVariable(&r_showoverdraw);
3216         Cvar_RegisterVariable(&r_showbboxes);
3217         Cvar_RegisterVariable(&r_showbboxes_client);
3218         Cvar_RegisterVariable(&r_showsurfaces);
3219         Cvar_RegisterVariable(&r_showtris);
3220         Cvar_RegisterVariable(&r_shownormals);
3221         Cvar_RegisterVariable(&r_showlighting);
3222         Cvar_RegisterVariable(&r_showcollisionbrushes);
3223         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
3224         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
3225         Cvar_RegisterVariable(&r_showdisabledepthtest);
3226         Cvar_RegisterVariable(&r_showspriteedges);
3227         Cvar_RegisterVariable(&r_showparticleedges);
3228         Cvar_RegisterVariable(&r_drawportals);
3229         Cvar_RegisterVariable(&r_drawentities);
3230         Cvar_RegisterVariable(&r_draw2d);
3231         Cvar_RegisterVariable(&r_drawworld);
3232         Cvar_RegisterVariable(&r_cullentities_trace);
3233         Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
3234         Cvar_RegisterVariable(&r_cullentities_trace_samples);
3235         Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
3236         Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
3237         Cvar_RegisterVariable(&r_cullentities_trace_expand);
3238         Cvar_RegisterVariable(&r_cullentities_trace_pad);
3239         Cvar_RegisterVariable(&r_cullentities_trace_delay);
3240         Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
3241         Cvar_RegisterVariable(&r_sortentities);
3242         Cvar_RegisterVariable(&r_drawviewmodel);
3243         Cvar_RegisterVariable(&r_drawexteriormodel);
3244         Cvar_RegisterVariable(&r_speeds);
3245         Cvar_RegisterVariable(&r_fullbrights);
3246         Cvar_RegisterVariable(&r_wateralpha);
3247         Cvar_RegisterVariable(&r_dynamic);
3248         Cvar_RegisterVariable(&r_fullbright_directed);
3249         Cvar_RegisterVariable(&r_fullbright_directed_ambient);
3250         Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
3251         Cvar_RegisterVariable(&r_fullbright_directed_pitch);
3252         Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
3253         Cvar_RegisterVariable(&r_fullbright);
3254         Cvar_RegisterVariable(&r_shadows);
3255         Cvar_RegisterVariable(&r_shadows_darken);
3256         Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
3257         Cvar_RegisterVariable(&r_shadows_castfrombmodels);
3258         Cvar_RegisterVariable(&r_shadows_throwdistance);
3259         Cvar_RegisterVariable(&r_shadows_throwdirection);
3260         Cvar_RegisterVariable(&r_shadows_focus);
3261         Cvar_RegisterVariable(&r_shadows_shadowmapscale);
3262         Cvar_RegisterVariable(&r_shadows_shadowmapbias);
3263         Cvar_RegisterVariable(&r_q1bsp_skymasking);
3264         Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
3265         Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
3266         Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
3267         Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
3268         Cvar_RegisterVariable(&r_fog_exp2);
3269         Cvar_RegisterVariable(&r_fog_clear);
3270         Cvar_RegisterVariable(&r_drawfog);
3271         Cvar_RegisterVariable(&r_transparentdepthmasking);
3272         Cvar_RegisterVariable(&r_transparent_sortmindist);
3273         Cvar_RegisterVariable(&r_transparent_sortmaxdist);
3274         Cvar_RegisterVariable(&r_transparent_sortarraysize);
3275         Cvar_RegisterVariable(&r_texture_dds_load);
3276         Cvar_RegisterVariable(&r_texture_dds_save);
3277         Cvar_RegisterVariable(&r_textureunits);
3278         Cvar_RegisterVariable(&gl_combine);
3279         Cvar_RegisterVariable(&r_usedepthtextures);
3280         Cvar_RegisterVariable(&r_viewfbo);
3281         Cvar_RegisterVariable(&r_rendertarget_debug);
3282         Cvar_RegisterVariable(&r_viewscale);
3283         Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3284         Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3285         Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3286         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3287         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3288         Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3289         Cvar_RegisterVariable(&r_glsl);
3290         Cvar_RegisterVariable(&r_glsl_deluxemapping);
3291         Cvar_RegisterVariable(&r_glsl_offsetmapping);
3292         Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3293         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3294         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3295         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3296         Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3297         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3298         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3299         Cvar_RegisterVariable(&r_glsl_postprocess);
3300         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3301         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3302         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3303         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3304         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3305         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3306         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3307         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3308         Cvar_RegisterVariable(&r_celshading);
3309         Cvar_RegisterVariable(&r_celoutlines);
3310
3311         Cvar_RegisterVariable(&r_water);
3312         Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3313         Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3314         Cvar_RegisterVariable(&r_water_clippingplanebias);
3315         Cvar_RegisterVariable(&r_water_refractdistort);
3316         Cvar_RegisterVariable(&r_water_reflectdistort);
3317         Cvar_RegisterVariable(&r_water_scissormode);
3318         Cvar_RegisterVariable(&r_water_lowquality);
3319         Cvar_RegisterVariable(&r_water_hideplayer);
3320
3321         Cvar_RegisterVariable(&r_lerpsprites);
3322         Cvar_RegisterVariable(&r_lerpmodels);
3323         Cvar_RegisterVariable(&r_lerplightstyles);
3324         Cvar_RegisterVariable(&r_waterscroll);
3325         Cvar_RegisterVariable(&r_bloom);
3326         Cvar_RegisterVariable(&r_colorfringe);
3327         Cvar_RegisterVariable(&r_bloom_colorscale);
3328         Cvar_RegisterVariable(&r_bloom_brighten);
3329         Cvar_RegisterVariable(&r_bloom_blur);
3330         Cvar_RegisterVariable(&r_bloom_resolution);
3331         Cvar_RegisterVariable(&r_bloom_colorexponent);
3332         Cvar_RegisterVariable(&r_bloom_colorsubtract);
3333         Cvar_RegisterVariable(&r_bloom_scenebrightness);
3334         Cvar_RegisterVariable(&r_hdr_scenebrightness);
3335         Cvar_RegisterVariable(&r_hdr_glowintensity);
3336         Cvar_RegisterVariable(&r_hdr_irisadaptation);
3337         Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3338         Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3339         Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3340         Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3341         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3342         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3343         Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3344         Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3345         Cvar_RegisterVariable(&developer_texturelogging);
3346         Cvar_RegisterVariable(&gl_lightmaps);
3347         Cvar_RegisterVariable(&r_test);
3348         Cvar_RegisterVariable(&r_batch_multidraw);
3349         Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3350         Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3351         Cvar_RegisterVariable(&r_glsl_skeletal);
3352         Cvar_RegisterVariable(&r_glsl_saturation);
3353         Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3354         Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3355         Cvar_RegisterVariable(&r_framedatasize);
3356         for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3357                 Cvar_RegisterVariable(&r_buffermegs[i]);
3358         Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3359         if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3360                 Cvar_SetValue(&cvars_all, "r_fullbrights", 0);
3361 #ifdef DP_MOBILETOUCH
3362         // GLES devices have terrible depth precision in general, so...
3363         Cvar_SetValueQuick(&r_nearclip, 4);
3364         Cvar_SetValueQuick(&r_farclip_base, 4096);
3365         Cvar_SetValueQuick(&r_farclip_world, 0);
3366         Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3367 #endif
3368         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3369 }
3370
3371 void Render_Init(void)
3372 {
3373         gl_backend_init();
3374         R_Textures_Init();
3375         GL_Main_Init();
3376         Font_Init();
3377         GL_Draw_Init();
3378         R_Shadow_Init();
3379         R_Sky_Init();
3380         GL_Surf_Init();
3381         Sbar_Init();
3382         R_Particles_Init();
3383         R_Explosion_Init();
3384         R_LightningBeams_Init();
3385         Mod_RenderInit();
3386 }
3387
3388 int R_CullBox(const vec3_t mins, const vec3_t maxs)
3389 {
3390         int i;
3391         mplane_t *p;
3392         if (r_trippy.integer)
3393                 return false;
3394         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
3395         {
3396                 p = r_refdef.view.frustum + i;
3397                 switch(p->signbits)
3398                 {
3399                 default:
3400                 case 0:
3401                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3402                                 return true;
3403                         break;
3404                 case 1:
3405                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3406                                 return true;
3407                         break;
3408                 case 2:
3409                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3410                                 return true;
3411                         break;
3412                 case 3:
3413                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3414                                 return true;
3415                         break;
3416                 case 4:
3417                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3418                                 return true;
3419                         break;
3420                 case 5:
3421                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3422                                 return true;
3423                         break;
3424                 case 6:
3425                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3426                                 return true;
3427                         break;
3428                 case 7:
3429                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3430                                 return true;
3431                         break;
3432                 }
3433         }
3434         return false;
3435 }
3436
3437 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3438 {
3439         int i;
3440         const mplane_t *p;
3441         if (r_trippy.integer)
3442                 return false;
3443         for (i = 0;i < numplanes;i++)
3444         {
3445                 p = planes + i;
3446                 switch(p->signbits)
3447                 {
3448                 default:
3449                 case 0:
3450                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3451                                 return true;
3452                         break;
3453                 case 1:
3454                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3455                                 return true;
3456                         break;
3457                 case 2:
3458                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3459                                 return true;
3460                         break;
3461                 case 3:
3462                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3463                                 return true;
3464                         break;
3465                 case 4:
3466                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3467                                 return true;
3468                         break;
3469                 case 5:
3470                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3471                                 return true;
3472                         break;
3473                 case 6:
3474                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3475                                 return true;
3476                         break;
3477                 case 7:
3478                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3479                                 return true;
3480                         break;
3481                 }
3482         }
3483         return false;
3484 }
3485
3486 //==================================================================================
3487
3488 // LadyHavoc: this stores temporary data used within the same frame
3489
3490 typedef struct r_framedata_mem_s
3491 {
3492         struct r_framedata_mem_s *purge; // older mem block to free on next frame
3493         size_t size; // how much usable space
3494         size_t current; // how much space in use
3495         size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3496         size_t wantedsize; // how much space was allocated
3497         unsigned char *data; // start of real data (16byte aligned)
3498 }
3499 r_framedata_mem_t;
3500
3501 static r_framedata_mem_t *r_framedata_mem;
3502
3503 void R_FrameData_Reset(void)
3504 {
3505         while (r_framedata_mem)
3506         {
3507                 r_framedata_mem_t *next = r_framedata_mem->purge;
3508                 Mem_Free(r_framedata_mem);
3509                 r_framedata_mem = next;
3510         }
3511 }
3512
3513 static void R_FrameData_Resize(qboolean mustgrow)
3514 {
3515         size_t wantedsize;
3516         wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3517         wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3518         if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3519         {
3520                 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3521                 newmem->wantedsize = wantedsize;
3522                 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3523                 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3524                 newmem->current = 0;
3525                 newmem->mark = 0;
3526                 newmem->purge = r_framedata_mem;
3527                 r_framedata_mem = newmem;
3528         }
3529 }
3530
3531 void R_FrameData_NewFrame(void)
3532 {
3533         R_FrameData_Resize(false);
3534         if (!r_framedata_mem)
3535                 return;
3536         // if we ran out of space on the last frame, free the old memory now
3537         while (r_framedata_mem->purge)
3538         {
3539                 // repeatedly remove the second item in the list, leaving only head
3540                 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3541                 Mem_Free(r_framedata_mem->purge);
3542                 r_framedata_mem->purge = next;
3543         }
3544         // reset the current mem pointer
3545         r_framedata_mem->current = 0;
3546         r_framedata_mem->mark = 0;
3547 }
3548
3549 void *R_FrameData_Alloc(size_t size)
3550 {
3551         void *data;
3552         float newvalue;
3553
3554         // align to 16 byte boundary - the data pointer is already aligned, so we
3555         // only need to ensure the size of every allocation is also aligned
3556         size = (size + 15) & ~15;
3557
3558         while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3559         {
3560                 // emergency - we ran out of space, allocate more memory
3561                 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3562                 newvalue = r_framedatasize.value * 2.0f;
3563                 // 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
3564                 if (sizeof(size_t) >= 8)
3565                         newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3566                 else
3567                         newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3568                 // this might not be a growing it, but we'll allocate another buffer every time
3569                 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3570                 R_FrameData_Resize(true);
3571         }
3572
3573         data = r_framedata_mem->data + r_framedata_mem->current;
3574         r_framedata_mem->current += size;
3575
3576         // count the usage for stats
3577         r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3578         r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3579
3580         return (void *)data;
3581 }
3582
3583 void *R_FrameData_Store(size_t size, void *data)
3584 {
3585         void *d = R_FrameData_Alloc(size);
3586         if (d && data)
3587                 memcpy(d, data, size);
3588         return d;
3589 }
3590
3591 void R_FrameData_SetMark(void)
3592 {
3593         if (!r_framedata_mem)
3594                 return;
3595         r_framedata_mem->mark = r_framedata_mem->current;
3596 }
3597
3598 void R_FrameData_ReturnToMark(void)
3599 {
3600         if (!r_framedata_mem)
3601                 return;
3602         r_framedata_mem->current = r_framedata_mem->mark;
3603 }
3604
3605 //==================================================================================
3606
3607 // avoid reusing the same buffer objects on consecutive frames
3608 #define R_BUFFERDATA_CYCLE 3
3609
3610 typedef struct r_bufferdata_buffer_s
3611 {
3612         struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3613         size_t size; // how much usable space
3614         size_t current; // how much space in use
3615         r_meshbuffer_t *buffer; // the buffer itself
3616 }
3617 r_bufferdata_buffer_t;
3618
3619 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3620 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3621
3622 /// frees all dynamic buffers
3623 void R_BufferData_Reset(void)
3624 {
3625         int cycle, type;
3626         r_bufferdata_buffer_t **p, *mem;
3627         for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3628         {
3629                 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3630                 {
3631                         // free all buffers
3632                         p = &r_bufferdata_buffer[cycle][type];
3633                         while (*p)
3634                         {
3635                                 mem = *p;
3636                                 *p = (*p)->purge;
3637                                 if (mem->buffer)
3638                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3639                                 Mem_Free(mem);
3640                         }
3641                 }
3642         }
3643 }
3644
3645 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3646 static void R_BufferData_Resize(r_bufferdata_type_t type, qboolean mustgrow, size_t minsize)
3647 {
3648         r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3649         size_t size;
3650         float newvalue = r_buffermegs[type].value;
3651
3652         // increase the cvar if we have to (but only if we already have a mem)
3653         if (mustgrow && mem)
3654                 newvalue *= 2.0f;
3655         newvalue = bound(0.25f, newvalue, 256.0f);
3656         while (newvalue * 1024*1024 < minsize)
3657                 newvalue *= 2.0f;
3658
3659         // clamp the cvar to valid range
3660         newvalue = bound(0.25f, newvalue, 256.0f);
3661         if (r_buffermegs[type].value != newvalue)
3662                 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3663
3664         // calculate size in bytes
3665         size = (size_t)(newvalue * 1024*1024);
3666         size = bound(131072, size, 256*1024*1024);
3667
3668         // allocate a new buffer if the size is different (purge old one later)
3669         // or if we were told we must grow the buffer
3670         if (!mem || mem->size != size || mustgrow)
3671         {
3672                 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3673                 mem->size = size;
3674                 mem->current = 0;
3675                 if (type == R_BUFFERDATA_VERTEX)
3676                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3677                 else if (type == R_BUFFERDATA_INDEX16)
3678                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3679                 else if (type == R_BUFFERDATA_INDEX32)
3680                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3681                 else if (type == R_BUFFERDATA_UNIFORM)
3682                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3683                 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3684                 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3685         }
3686 }
3687
3688 void R_BufferData_NewFrame(void)
3689 {
3690         int type;
3691         r_bufferdata_buffer_t **p, *mem;
3692         // cycle to the next frame's buffers
3693         r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3694         // if we ran out of space on the last time we used these buffers, free the old memory now
3695         for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3696         {
3697                 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3698                 {
3699                         R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3700                         // free all but the head buffer, this is how we recycle obsolete
3701                         // buffers after they are no longer in use
3702                         p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3703                         while (*p)
3704                         {
3705                                 mem = *p;
3706                                 *p = (*p)->purge;
3707                                 if (mem->buffer)
3708                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3709                                 Mem_Free(mem);
3710                         }
3711                         // reset the current offset
3712                         r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3713                 }
3714         }
3715 }
3716
3717 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3718 {
3719         r_bufferdata_buffer_t *mem;
3720         int offset = 0;
3721         int padsize;
3722
3723         *returnbufferoffset = 0;
3724
3725         // align size to a byte boundary appropriate for the buffer type, this
3726         // makes all allocations have aligned start offsets
3727         if (type == R_BUFFERDATA_UNIFORM)
3728                 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3729         else
3730                 padsize = (datasize + 15) & ~15;
3731
3732         // if we ran out of space in this buffer we must allocate a new one
3733         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)
3734                 R_BufferData_Resize(type, true, padsize);
3735
3736         // if the resize did not give us enough memory, fail
3737         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)
3738                 Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3739
3740         mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3741         offset = (int)mem->current;
3742         mem->current += padsize;
3743
3744         // upload the data to the buffer at the chosen offset
3745         if (offset == 0)
3746                 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3747         R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3748
3749         // count the usage for stats
3750         r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3751         r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3752
3753         // return the buffer offset
3754         *returnbufferoffset = offset;
3755
3756         return mem->buffer;
3757 }
3758
3759 //==================================================================================
3760
3761 // LadyHavoc: animcache originally written by Echon, rewritten since then
3762
3763 /**
3764  * Animation cache prevents re-generating mesh data for an animated model
3765  * multiple times in one frame for lighting, shadowing, reflections, etc.
3766  */
3767
3768 void R_AnimCache_Free(void)
3769 {
3770 }
3771
3772 void R_AnimCache_ClearCache(void)
3773 {
3774         int i;
3775         entity_render_t *ent;
3776
3777         for (i = 0;i < r_refdef.scene.numentities;i++)
3778         {
3779                 ent = r_refdef.scene.entities[i];
3780                 ent->animcache_vertex3f = NULL;
3781                 ent->animcache_vertex3f_vertexbuffer = NULL;
3782                 ent->animcache_vertex3f_bufferoffset = 0;
3783                 ent->animcache_normal3f = NULL;
3784                 ent->animcache_normal3f_vertexbuffer = NULL;
3785                 ent->animcache_normal3f_bufferoffset = 0;
3786                 ent->animcache_svector3f = NULL;
3787                 ent->animcache_svector3f_vertexbuffer = NULL;
3788                 ent->animcache_svector3f_bufferoffset = 0;
3789                 ent->animcache_tvector3f = NULL;
3790                 ent->animcache_tvector3f_vertexbuffer = NULL;
3791                 ent->animcache_tvector3f_bufferoffset = 0;
3792                 ent->animcache_skeletaltransform3x4 = NULL;
3793                 ent->animcache_skeletaltransform3x4buffer = NULL;
3794                 ent->animcache_skeletaltransform3x4offset = 0;
3795                 ent->animcache_skeletaltransform3x4size = 0;
3796         }
3797 }
3798
3799 qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
3800 {
3801         dp_model_t *model = ent->model;
3802         int numvertices;
3803
3804         // see if this ent is worth caching
3805         if (!model || !model->Draw || !model->AnimateVertices)
3806                 return false;
3807         // nothing to cache if it contains no animations and has no skeleton
3808         if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3809                 return false;
3810         // see if it is already cached for gpuskeletal
3811         if (ent->animcache_skeletaltransform3x4)
3812                 return false;
3813         // see if it is already cached as a mesh
3814         if (ent->animcache_vertex3f)
3815         {
3816                 // check if we need to add normals or tangents
3817                 if (ent->animcache_normal3f)
3818                         wantnormals = false;
3819                 if (ent->animcache_svector3f)
3820                         wanttangents = false;
3821                 if (!wantnormals && !wanttangents)
3822                         return false;
3823         }
3824
3825         // check which kind of cache we need to generate
3826         if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3827         {
3828                 // cache the skeleton so the vertex shader can use it
3829                 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3830                 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3831                 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3832                 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3833                 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4); 
3834                 // note: this can fail if the buffer is at the grow limit
3835                 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3836                 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3837         }
3838         else if (ent->animcache_vertex3f)
3839         {
3840                 // mesh was already cached but we may need to add normals/tangents
3841                 // (this only happens with multiple views, reflections, cameras, etc)
3842                 if (wantnormals || wanttangents)
3843                 {
3844                         numvertices = model->surfmesh.num_vertices;
3845                         if (wantnormals)
3846                                 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3847                         if (wanttangents)
3848                         {
3849                                 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3850                                 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3851                         }
3852                         model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3853                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3854                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3855                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3856                 }
3857         }
3858         else
3859         {
3860                 // generate mesh cache
3861                 numvertices = model->surfmesh.num_vertices;
3862                 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3863                 if (wantnormals)
3864                         ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3865                 if (wanttangents)
3866                 {
3867                         ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3868                         ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3869                 }
3870                 model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
3871                 if (wantnormals || wanttangents)
3872                 {
3873                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3874                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3875                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3876                 }
3877                 r_refdef.stats[r_stat_animcache_shape_count] += 1;
3878                 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
3879                 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
3880         }
3881         return true;
3882 }
3883
3884 void R_AnimCache_CacheVisibleEntities(void)
3885 {
3886         int i;
3887
3888         // TODO: thread this
3889         // NOTE: R_PrepareRTLights() also caches entities
3890
3891         for (i = 0;i < r_refdef.scene.numentities;i++)
3892                 if (r_refdef.viewcache.entityvisible[i])
3893                         R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
3894 }
3895
3896 //==================================================================================
3897
3898 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)
3899 {
3900         int i;
3901         vec3_t eyemins, eyemaxs;
3902         vec3_t boxmins, boxmaxs;
3903         vec3_t padmins, padmaxs;
3904         vec3_t start;
3905         vec3_t end;
3906         dp_model_t *model = r_refdef.scene.worldmodel;
3907         static vec3_t positions[] = {
3908                 { 0.5f, 0.5f, 0.5f },
3909                 { 0.0f, 0.0f, 0.0f },
3910                 { 0.0f, 0.0f, 1.0f },
3911                 { 0.0f, 1.0f, 0.0f },
3912                 { 0.0f, 1.0f, 1.0f },
3913                 { 1.0f, 0.0f, 0.0f },
3914                 { 1.0f, 0.0f, 1.0f },
3915                 { 1.0f, 1.0f, 0.0f },
3916                 { 1.0f, 1.0f, 1.0f },
3917         };
3918
3919         // sample count can be set to -1 to skip this logic, for flicker-prone objects
3920         if (numsamples < 0)
3921                 return true;
3922
3923         // view origin is not used for culling in portal/reflection/refraction renders or isometric views
3924         if (!r_refdef.view.usevieworiginculling)
3925                 return true;
3926
3927         if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
3928                 return true;
3929
3930         // expand the eye box a little
3931         eyemins[0] = eye[0] - eyejitter;
3932         eyemaxs[0] = eye[0] + eyejitter;
3933         eyemins[1] = eye[1] - eyejitter;
3934         eyemaxs[1] = eye[1] + eyejitter;
3935         eyemins[2] = eye[2] - eyejitter;
3936         eyemaxs[2] = eye[2] + eyejitter;
3937         // expand the box a little
3938         boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
3939         boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
3940         boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
3941         boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
3942         boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
3943         boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
3944         // make an even larger box for the acceptable area
3945         padmins[0] = boxmins[0] - pad;
3946         padmaxs[0] = boxmaxs[0] + pad;
3947         padmins[1] = boxmins[1] - pad;
3948         padmaxs[1] = boxmaxs[1] + pad;
3949         padmins[2] = boxmins[2] - pad;
3950         padmaxs[2] = boxmaxs[2] + pad;
3951
3952         // return true if eye overlaps enlarged box
3953         if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
3954                 return true;
3955
3956         // try specific positions in the box first - note that these can be cached
3957         if (r_cullentities_trace_entityocclusion.integer)
3958         {
3959                 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
3960                 {
3961                         VectorCopy(eye, start);
3962                         end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
3963                         end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
3964                         end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
3965                         //trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
3966                         trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
3967                         // not picky - if the trace ended anywhere in the box we're good
3968                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
3969                                 return true;
3970                 }
3971         }
3972         else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
3973                 return true;
3974
3975         // try various random positions
3976         for (i = 0; i < numsamples; i++)
3977         {
3978                 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
3979                 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
3980                 if (r_cullentities_trace_entityocclusion.integer)
3981                 {
3982                         trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
3983                         // not picky - if the trace ended anywhere in the box we're good
3984                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
3985                                 return true;
3986                 }
3987                 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
3988                         return true;
3989         }
3990
3991         return false;
3992 }
3993
3994
3995 static void R_View_UpdateEntityVisible (void)
3996 {
3997         int i;
3998         int renderimask;
3999         int samples;
4000         entity_render_t *ent;
4001
4002         if (r_refdef.envmap || r_fb.water.hideplayer)
4003                 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
4004         else if (chase_active.integer || r_fb.water.renderingscene)
4005                 renderimask = RENDER_VIEWMODEL;
4006         else
4007                 renderimask = RENDER_EXTERIORMODEL;
4008         if (!r_drawviewmodel.integer)
4009                 renderimask |= RENDER_VIEWMODEL;
4010         if (!r_drawexteriormodel.integer)
4011                 renderimask |= RENDER_EXTERIORMODEL;
4012         memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4013         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4014         {
4015                 // worldmodel can check visibility
4016                 for (i = 0;i < r_refdef.scene.numentities;i++)
4017                 {
4018                         ent = r_refdef.scene.entities[i];
4019                         if (!(ent->flags & renderimask))
4020                         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)))
4021                         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))
4022                                 r_refdef.viewcache.entityvisible[i] = true;
4023                 }
4024         }
4025         else
4026         {
4027                 // no worldmodel or it can't check visibility
4028                 for (i = 0;i < r_refdef.scene.numentities;i++)
4029                 {
4030                         ent = r_refdef.scene.entities[i];
4031                         if (!(ent->flags & renderimask))
4032                         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)))
4033                                 r_refdef.viewcache.entityvisible[i] = true;
4034                 }
4035         }
4036         if (r_cullentities_trace.integer)
4037         {
4038                 for (i = 0;i < r_refdef.scene.numentities;i++)
4039                 {
4040                         if (!r_refdef.viewcache.entityvisible[i])
4041                                 continue;
4042                         ent = r_refdef.scene.entities[i];
4043                         if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4044                         {
4045                                 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4046                                 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))
4047                                         ent->last_trace_visibility = realtime;
4048                                 if (ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
4049                                         r_refdef.viewcache.entityvisible[i] = 0;
4050                         }
4051                 }
4052         }
4053 }
4054
4055 /// only used if skyrendermasked, and normally returns false
4056 static int R_DrawBrushModelsSky (void)
4057 {
4058         int i, sky;
4059         entity_render_t *ent;
4060
4061         sky = false;
4062         for (i = 0;i < r_refdef.scene.numentities;i++)
4063         {
4064                 if (!r_refdef.viewcache.entityvisible[i])
4065                         continue;
4066                 ent = r_refdef.scene.entities[i];
4067                 if (!ent->model || !ent->model->DrawSky)
4068                         continue;
4069                 ent->model->DrawSky(ent);
4070                 sky = true;
4071         }
4072         return sky;
4073 }
4074
4075 static void R_DrawNoModel(entity_render_t *ent);
4076 static void R_DrawModels(void)
4077 {
4078         int i;
4079         entity_render_t *ent;
4080
4081         for (i = 0;i < r_refdef.scene.numentities;i++)
4082         {
4083                 if (!r_refdef.viewcache.entityvisible[i])
4084                         continue;
4085                 ent = r_refdef.scene.entities[i];
4086                 r_refdef.stats[r_stat_entities]++;
4087                 /*
4088                 if (ent->model && !strncmp(ent->model->name, "models/proto_", 13))
4089                 {
4090                         vec3_t f, l, u, o;
4091                         Matrix4x4_ToVectors(&ent->matrix, f, l, u, o);
4092                         Con_Printf("R_DrawModels\n");
4093                         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]);
4094                         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);
4095                         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);
4096                 }
4097                 */
4098                 if (ent->model && ent->model->Draw != NULL)
4099                         ent->model->Draw(ent);
4100                 else
4101                         R_DrawNoModel(ent);
4102         }
4103 }
4104
4105 static void R_DrawModelsDepth(void)
4106 {
4107         int i;
4108         entity_render_t *ent;
4109
4110         for (i = 0;i < r_refdef.scene.numentities;i++)
4111         {
4112                 if (!r_refdef.viewcache.entityvisible[i])
4113                         continue;
4114                 ent = r_refdef.scene.entities[i];
4115                 if (ent->model && ent->model->DrawDepth != NULL)
4116                         ent->model->DrawDepth(ent);
4117         }
4118 }
4119
4120 static void R_DrawModelsDebug(void)
4121 {
4122         int i;
4123         entity_render_t *ent;
4124
4125         for (i = 0;i < r_refdef.scene.numentities;i++)
4126         {
4127                 if (!r_refdef.viewcache.entityvisible[i])
4128                         continue;
4129                 ent = r_refdef.scene.entities[i];
4130                 if (ent->model && ent->model->DrawDebug != NULL)
4131                         ent->model->DrawDebug(ent);
4132         }
4133 }
4134
4135 static void R_DrawModelsAddWaterPlanes(void)
4136 {
4137         int i;
4138         entity_render_t *ent;
4139
4140         for (i = 0;i < r_refdef.scene.numentities;i++)
4141         {
4142                 if (!r_refdef.viewcache.entityvisible[i])
4143                         continue;
4144                 ent = r_refdef.scene.entities[i];
4145                 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4146                         ent->model->DrawAddWaterPlanes(ent);
4147         }
4148 }
4149
4150 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}};
4151
4152 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4153 {
4154         if (r_hdr_irisadaptation.integer)
4155         {
4156                 vec3_t p;
4157                 vec3_t ambient;
4158                 vec3_t diffuse;
4159                 vec3_t diffusenormal;
4160                 vec3_t forward;
4161                 vec_t brightness = 0.0f;
4162                 vec_t goal;
4163                 vec_t current;
4164                 vec_t d;
4165                 int c;
4166                 VectorCopy(r_refdef.view.forward, forward);
4167                 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4168                 {
4169                         p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4170                         p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4171                         p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4172                         R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4173                         d = DotProduct(forward, diffusenormal);
4174                         brightness += VectorLength(ambient);
4175                         if (d > 0)
4176                                 brightness += d * VectorLength(diffuse);
4177                 }
4178                 brightness *= 1.0f / c;
4179                 brightness += 0.00001f; // make sure it's never zero
4180                 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4181                 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4182                 current = r_hdr_irisadaptation_value.value;
4183                 if (current < goal)
4184                         current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4185                 else if (current > goal)
4186                         current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4187                 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4188                         Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4189         }
4190         else if (r_hdr_irisadaptation_value.value != 1.0f)
4191                 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4192 }
4193
4194 static void R_View_SetFrustum(const int *scissor)
4195 {
4196         int i;
4197         double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4198         vec3_t forward, left, up, origin, v;
4199
4200         if(scissor)
4201         {
4202                 // flipped x coordinates (because x points left here)
4203                 fpx =  1.0 - 2.0 * (scissor[0]              - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4204                 fnx =  1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4205                 // non-flipped y coordinates
4206                 fny = -1.0 + 2.0 * (scissor[1]              - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4207                 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4208         }
4209
4210         // we can't trust r_refdef.view.forward and friends in reflected scenes
4211         Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4212
4213 #if 0
4214         r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4215         r_refdef.view.frustum[0].normal[1] = 0 - 0;
4216         r_refdef.view.frustum[0].normal[2] = -1 - 0;
4217         r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4218         r_refdef.view.frustum[1].normal[1] = 0 + 0;
4219         r_refdef.view.frustum[1].normal[2] = -1 + 0;
4220         r_refdef.view.frustum[2].normal[0] = 0 - 0;
4221         r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4222         r_refdef.view.frustum[2].normal[2] = -1 - 0;
4223         r_refdef.view.frustum[3].normal[0] = 0 + 0;
4224         r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4225         r_refdef.view.frustum[3].normal[2] = -1 + 0;
4226 #endif
4227
4228 #if 0
4229         zNear = r_refdef.nearclip;
4230         nudge = 1.0 - 1.0 / (1<<23);
4231         r_refdef.view.frustum[4].normal[0] = 0 - 0;
4232         r_refdef.view.frustum[4].normal[1] = 0 - 0;
4233         r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4234         r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4235         r_refdef.view.frustum[5].normal[0] = 0 + 0;
4236         r_refdef.view.frustum[5].normal[1] = 0 + 0;
4237         r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4238         r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4239 #endif
4240
4241
4242
4243 #if 0
4244         r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4245         r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4246         r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4247         r_refdef.view.frustum[0].dist = m[15] - m[12];
4248
4249         r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4250         r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4251         r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4252         r_refdef.view.frustum[1].dist = m[15] + m[12];
4253
4254         r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4255         r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4256         r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4257         r_refdef.view.frustum[2].dist = m[15] - m[13];
4258
4259         r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4260         r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4261         r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4262         r_refdef.view.frustum[3].dist = m[15] + m[13];
4263
4264         r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4265         r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4266         r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4267         r_refdef.view.frustum[4].dist = m[15] - m[14];
4268
4269         r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4270         r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4271         r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4272         r_refdef.view.frustum[5].dist = m[15] + m[14];
4273 #endif
4274
4275         if (r_refdef.view.useperspective)
4276         {
4277                 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4278                 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]);
4279                 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]);
4280                 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]);
4281                 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]);
4282
4283                 // then the normals from the corners relative to origin
4284                 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4285                 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4286                 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4287                 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4288
4289                 // in a NORMAL view, forward cross left == up
4290                 // in a REFLECTED view, forward cross left == down
4291                 // so our cross products above need to be adjusted for a left handed coordinate system
4292                 CrossProduct(forward, left, v);
4293                 if(DotProduct(v, up) < 0)
4294                 {
4295                         VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4296                         VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4297                         VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4298                         VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4299                 }
4300
4301                 // Leaving those out was a mistake, those were in the old code, and they
4302                 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4303                 // I couldn't reproduce it after adding those normalizations. --blub
4304                 VectorNormalize(r_refdef.view.frustum[0].normal);
4305                 VectorNormalize(r_refdef.view.frustum[1].normal);
4306                 VectorNormalize(r_refdef.view.frustum[2].normal);
4307                 VectorNormalize(r_refdef.view.frustum[3].normal);
4308
4309                 // make the corners absolute
4310                 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4311                 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4312                 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4313                 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4314
4315                 // one more normal
4316                 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4317
4318                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4319                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4320                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4321                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4322                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4323         }
4324         else
4325         {
4326                 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4327                 VectorScale(left,  1.0f, r_refdef.view.frustum[1].normal);
4328                 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4329                 VectorScale(up,  1.0f, r_refdef.view.frustum[3].normal);
4330                 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4331                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4332                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4333                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4334                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4335                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4336         }
4337         r_refdef.view.numfrustumplanes = 5;
4338
4339         if (r_refdef.view.useclipplane)
4340         {
4341                 r_refdef.view.numfrustumplanes = 6;
4342                 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4343         }
4344
4345         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4346                 PlaneClassify(r_refdef.view.frustum + i);
4347
4348         // LadyHavoc: note to all quake engine coders, Quake had a special case
4349         // for 90 degrees which assumed a square view (wrong), so I removed it,
4350         // Quake2 has it disabled as well.
4351
4352         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4353         //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4354         //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4355         //PlaneClassify(&frustum[0]);
4356
4357         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4358         //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4359         //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4360         //PlaneClassify(&frustum[1]);
4361
4362         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4363         //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4364         //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4365         //PlaneClassify(&frustum[2]);
4366
4367         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4368         //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4369         //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4370         //PlaneClassify(&frustum[3]);
4371
4372         // nearclip plane
4373         //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4374         //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4375         //PlaneClassify(&frustum[4]);
4376 }
4377
4378 static void R_View_UpdateWithScissor(const int *myscissor)
4379 {
4380         R_Main_ResizeViewCache();
4381         R_View_SetFrustum(myscissor);
4382         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4383         R_View_UpdateEntityVisible();
4384 }
4385
4386 static void R_View_Update(void)
4387 {
4388         R_Main_ResizeViewCache();
4389         R_View_SetFrustum(NULL);
4390         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4391         R_View_UpdateEntityVisible();
4392 }
4393
4394 float viewscalefpsadjusted = 1.0f;
4395
4396 void R_SetupView(qboolean allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4397 {
4398         const float *customclipplane = NULL;
4399         float plane[4];
4400         int /*rtwidth,*/ rtheight;
4401         if (r_refdef.view.useclipplane && allowwaterclippingplane)
4402         {
4403                 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4404                 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4405                 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4406                 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4407                         dist = r_refdef.view.clipplane.dist;
4408                 plane[0] = r_refdef.view.clipplane.normal[0];
4409                 plane[1] = r_refdef.view.clipplane.normal[1];
4410                 plane[2] = r_refdef.view.clipplane.normal[2];
4411                 plane[3] = -dist;
4412                 customclipplane = plane;
4413         }
4414
4415         //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
4416         rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
4417
4418         if (!r_refdef.view.useperspective)
4419                 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);
4420         else if (vid.stencil && r_useinfinitefarclip.integer)
4421                 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);
4422         else
4423                 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);
4424         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4425         R_SetViewport(&r_refdef.view.viewport);
4426 }
4427
4428 void R_EntityMatrix(const matrix4x4_t *matrix)
4429 {
4430         if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4431         {
4432                 gl_modelmatrixchanged = false;
4433                 gl_modelmatrix = *matrix;
4434                 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4435                 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4436                 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4437                 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4438                 CHECKGLERROR
4439                 switch(vid.renderpath)
4440                 {
4441                 case RENDERPATH_GL32:
4442                 case RENDERPATH_GLES2:
4443                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4444                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4445                         break;
4446                 }
4447         }
4448 }
4449
4450 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4451 {
4452         r_viewport_t viewport;
4453
4454         CHECKGLERROR
4455
4456         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
4457         R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4458         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4459         R_SetViewport(&viewport);
4460         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4461         GL_Color(1, 1, 1, 1);
4462         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4463         GL_BlendFunc(GL_ONE, GL_ZERO);
4464         GL_ScissorTest(false);
4465         GL_DepthMask(false);
4466         GL_DepthRange(0, 1);
4467         GL_DepthTest(false);
4468         GL_DepthFunc(GL_LEQUAL);
4469         R_EntityMatrix(&identitymatrix);
4470         R_Mesh_ResetTextureState();
4471         GL_PolygonOffset(0, 0);
4472         switch(vid.renderpath)
4473         {
4474         case RENDERPATH_GL32:
4475         case RENDERPATH_GLES2:
4476                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4477                 break;
4478         }
4479         GL_CullFace(GL_NONE);
4480
4481         CHECKGLERROR
4482 }
4483
4484 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4485 {
4486         R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4487 }
4488
4489 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4490 {
4491         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4492         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4493         GL_Color(1, 1, 1, 1);
4494         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4495         GL_BlendFunc(GL_ONE, GL_ZERO);
4496         GL_ScissorTest(true);
4497         GL_DepthMask(true);
4498         GL_DepthRange(0, 1);
4499         GL_DepthTest(true);
4500         GL_DepthFunc(GL_LEQUAL);
4501         R_EntityMatrix(&identitymatrix);
4502         R_Mesh_ResetTextureState();
4503         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4504         switch(vid.renderpath)
4505         {
4506         case RENDERPATH_GL32:
4507         case RENDERPATH_GLES2:
4508                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4509                 break;
4510         }
4511         GL_CullFace(r_refdef.view.cullface_back);
4512 }
4513
4514 /*
4515 ================
4516 R_RenderView_UpdateViewVectors
4517 ================
4518 */
4519 void R_RenderView_UpdateViewVectors(void)
4520 {
4521         // break apart the view matrix into vectors for various purposes
4522         // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4523         // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4524         Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4525         VectorNegate(r_refdef.view.left, r_refdef.view.right);
4526         // make an inverted copy of the view matrix for tracking sprites
4527         Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4528 }
4529
4530 void R_RenderTarget_FreeUnused(qboolean force)
4531 {
4532         unsigned int i, j, end;
4533         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4534         for (i = 0; i < end; i++)
4535         {
4536                 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4537                 // free resources for rendertargets that have not been used for a while
4538                 // (note: this check is run after the frame render, so any targets used
4539                 // this frame will not be affected even at low framerates)
4540                 if (r && (realtime - r->lastusetime > 0.2 || force))
4541                 {
4542                         if (r->fbo)
4543                                 R_Mesh_DestroyFramebufferObject(r->fbo);
4544                         for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4545                                 if (r->colortexture[j])
4546                                         R_FreeTexture(r->colortexture[j]);
4547                         if (r->depthtexture)
4548                                 R_FreeTexture(r->depthtexture);
4549                         Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4550                 }
4551         }
4552 }
4553
4554 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4555 {
4556         float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4557         x1 = x * iw;
4558         x2 = (x + w) * iw;
4559         y1 = (th - y) * ih;
4560         y2 = (th - y - h) * ih;
4561         texcoord2f[0] = x1;
4562         texcoord2f[2] = x2;
4563         texcoord2f[4] = x2;
4564         texcoord2f[6] = x1;
4565         texcoord2f[1] = y1;
4566         texcoord2f[3] = y1;
4567         texcoord2f[5] = y2;
4568         texcoord2f[7] = y2;
4569 }
4570
4571 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)
4572 {
4573         unsigned int i, j, end;
4574         r_rendertarget_t *r = NULL;
4575         char vabuf[256];
4576         // first try to reuse an existing slot if possible
4577         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4578         for (i = 0; i < end; i++)
4579         {
4580                 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4581                 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)
4582                         break;
4583         }
4584         if (i == end)
4585         {
4586                 // no unused exact match found, so we have to make one in the first unused slot
4587                 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4588                 r->texturewidth = texturewidth;
4589                 r->textureheight = textureheight;
4590                 r->colortextype[0] = colortextype0;
4591                 r->colortextype[1] = colortextype1;
4592                 r->colortextype[2] = colortextype2;
4593                 r->colortextype[3] = colortextype3;
4594                 r->depthtextype = depthtextype;
4595                 r->depthisrenderbuffer = depthisrenderbuffer;
4596                 for (j = 0; j < 4; j++)
4597                         if (r->colortextype[j])
4598                                 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);
4599                 if (r->depthtextype)
4600                 {
4601                         if (r->depthisrenderbuffer)
4602                                 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);
4603                         else
4604                                 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);
4605                 }
4606                 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4607         }
4608         r_refdef.stats[r_stat_rendertargets_used]++;
4609         r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4610         r->lastusetime = realtime;
4611         R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4612         return r;
4613 }
4614
4615 static void R_Water_StartFrame(int viewwidth, int viewheight)
4616 {
4617         int waterwidth, waterheight;
4618
4619         if (vid.width > (int)vid.maxtexturesize_2d || vid.height > (int)vid.maxtexturesize_2d)
4620                 return;
4621
4622         // set waterwidth and waterheight to the water resolution that will be
4623         // used (often less than the screen resolution for faster rendering)
4624         waterwidth = (int)bound(16, viewwidth * r_water_resolutionmultiplier.value, viewwidth);
4625         waterheight = (int)bound(16, viewheight * r_water_resolutionmultiplier.value, viewheight);
4626
4627         if (!r_water.integer || r_showsurfaces.integer)
4628                 waterwidth = waterheight = 0;
4629
4630         // set up variables that will be used in shader setup
4631         r_fb.water.waterwidth = waterwidth;
4632         r_fb.water.waterheight = waterheight;
4633         r_fb.water.texturewidth = waterwidth;
4634         r_fb.water.textureheight = waterheight;
4635         r_fb.water.camerawidth = waterwidth;
4636         r_fb.water.cameraheight = waterheight;
4637         r_fb.water.screenscale[0] = 0.5f;
4638         r_fb.water.screenscale[1] = 0.5f;
4639         r_fb.water.screencenter[0] = 0.5f;
4640         r_fb.water.screencenter[1] = 0.5f;
4641         r_fb.water.enabled = waterwidth != 0;
4642
4643         r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4644         r_fb.water.numwaterplanes = 0;
4645 }
4646
4647 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4648 {
4649         int planeindex, bestplaneindex, vertexindex;
4650         vec3_t mins, maxs, normal, center, v, n;
4651         vec_t planescore, bestplanescore;
4652         mplane_t plane;
4653         r_waterstate_waterplane_t *p;
4654         texture_t *t = R_GetCurrentTexture(surface->texture);
4655
4656         rsurface.texture = t;
4657         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4658         // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4659         if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4660                 return;
4661         // average the vertex normals, find the surface bounds (after deformvertexes)
4662         Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4663         Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4664         VectorCopy(n, normal);
4665         VectorCopy(v, mins);
4666         VectorCopy(v, maxs);
4667         for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4668         {
4669                 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4670                 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4671                 VectorAdd(normal, n, normal);
4672                 mins[0] = min(mins[0], v[0]);
4673                 mins[1] = min(mins[1], v[1]);
4674                 mins[2] = min(mins[2], v[2]);
4675                 maxs[0] = max(maxs[0], v[0]);
4676                 maxs[1] = max(maxs[1], v[1]);
4677                 maxs[2] = max(maxs[2], v[2]);
4678         }
4679         VectorNormalize(normal);
4680         VectorMAM(0.5f, mins, 0.5f, maxs, center);
4681
4682         VectorCopy(normal, plane.normal);
4683         VectorNormalize(plane.normal);
4684         plane.dist = DotProduct(center, plane.normal);
4685         PlaneClassify(&plane);
4686         if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4687         {
4688                 // skip backfaces (except if nocullface is set)
4689 //              if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4690 //                      return;
4691                 VectorNegate(plane.normal, plane.normal);
4692                 plane.dist *= -1;
4693                 PlaneClassify(&plane);
4694         }
4695
4696
4697         // find a matching plane if there is one
4698         bestplaneindex = -1;
4699         bestplanescore = 1048576.0f;
4700         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4701         {
4702                 if(p->camera_entity == t->camera_entity)
4703                 {
4704                         planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4705                         if (bestplaneindex < 0 || bestplanescore > planescore)
4706                         {
4707                                 bestplaneindex = planeindex;
4708                                 bestplanescore = planescore;
4709                         }
4710                 }
4711         }
4712         planeindex = bestplaneindex;
4713
4714         // if this surface does not fit any known plane rendered this frame, add one
4715         if (planeindex < 0 || bestplanescore > 0.001f)
4716         {
4717                 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4718                 {
4719                         // store the new plane
4720                         planeindex = r_fb.water.numwaterplanes++;
4721                         p = r_fb.water.waterplanes + planeindex;
4722                         p->plane = plane;
4723                         // clear materialflags and pvs
4724                         p->materialflags = 0;
4725                         p->pvsvalid = false;
4726                         p->camera_entity = t->camera_entity;
4727                         VectorCopy(mins, p->mins);
4728                         VectorCopy(maxs, p->maxs);
4729                 }
4730                 else
4731                 {
4732                         // We're totally screwed.
4733                         return;
4734                 }
4735         }
4736         else
4737         {
4738                 // merge mins/maxs when we're adding this surface to the plane
4739                 p = r_fb.water.waterplanes + planeindex;
4740                 p->mins[0] = min(p->mins[0], mins[0]);
4741                 p->mins[1] = min(p->mins[1], mins[1]);
4742                 p->mins[2] = min(p->mins[2], mins[2]);
4743                 p->maxs[0] = max(p->maxs[0], maxs[0]);
4744                 p->maxs[1] = max(p->maxs[1], maxs[1]);
4745                 p->maxs[2] = max(p->maxs[2], maxs[2]);
4746         }
4747         // merge this surface's materialflags into the waterplane
4748         p->materialflags |= t->currentmaterialflags;
4749         if(!(p->materialflags & MATERIALFLAG_CAMERA))
4750         {
4751                 // merge this surface's PVS into the waterplane
4752                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4753                  && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4754                 {
4755                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4756                         p->pvsvalid = true;
4757                 }
4758         }
4759 }
4760
4761 extern cvar_t r_drawparticles;
4762 extern cvar_t r_drawdecals;
4763
4764 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4765 {
4766         int myscissor[4];
4767         r_refdef_view_t originalview;
4768         r_refdef_view_t myview;
4769         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;
4770         r_waterstate_waterplane_t *p;
4771         vec3_t visorigin;
4772         r_rendertarget_t *rt;
4773
4774         originalview = r_refdef.view;
4775
4776         // lowquality hack, temporarily shut down some cvars and restore afterwards
4777         qualityreduction = r_water_lowquality.integer;
4778         if (qualityreduction > 0)
4779         {
4780                 if (qualityreduction >= 1)
4781                 {
4782                         old_r_shadows = r_shadows.integer;
4783                         old_r_worldrtlight = r_shadow_realtime_world.integer;
4784                         old_r_dlight = r_shadow_realtime_dlight.integer;
4785                         Cvar_SetValueQuick(&r_shadows, 0);
4786                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4787                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4788                 }
4789                 if (qualityreduction >= 2)
4790                 {
4791                         old_r_dynamic = r_dynamic.integer;
4792                         old_r_particles = r_drawparticles.integer;
4793                         old_r_decals = r_drawdecals.integer;
4794                         Cvar_SetValueQuick(&r_dynamic, 0);
4795                         Cvar_SetValueQuick(&r_drawparticles, 0);
4796                         Cvar_SetValueQuick(&r_drawdecals, 0);
4797                 }
4798         }
4799
4800         for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4801         {
4802                 p->rt_reflection = NULL;
4803                 p->rt_refraction = NULL;
4804                 p->rt_camera = NULL;
4805         }
4806
4807         // render views
4808         r_refdef.view = originalview;
4809         r_refdef.view.showdebug = false;
4810         r_refdef.view.width = r_fb.water.waterwidth;
4811         r_refdef.view.height = r_fb.water.waterheight;
4812         r_refdef.view.useclipplane = true;
4813         myview = r_refdef.view;
4814         r_fb.water.renderingscene = true;
4815         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4816         {
4817                 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4818                         continue;
4819
4820                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4821                 {
4822                         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);
4823                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4824                                 goto error;
4825                         r_refdef.view = myview;
4826                         Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4827                         Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4828                         if(r_water_scissormode.integer)
4829                         {
4830                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4831                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4832                                 {
4833                                         p->rt_reflection = NULL;
4834                                         p->rt_refraction = NULL;
4835                                         p->rt_camera = NULL;
4836                                         continue;
4837                                 }
4838                         }
4839
4840                         r_refdef.view.clipplane = p->plane;
4841                         // reflected view origin may be in solid, so don't cull with it
4842                         r_refdef.view.usevieworiginculling = false;
4843                         // reverse the cullface settings for this render
4844                         r_refdef.view.cullface_front = GL_FRONT;
4845                         r_refdef.view.cullface_back = GL_BACK;
4846                         // combined pvs (based on what can be seen from each surface center)
4847                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4848                         {
4849                                 r_refdef.view.usecustompvs = true;
4850                                 if (p->pvsvalid)
4851                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4852                                 else
4853                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4854                         }
4855
4856                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4857                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4858                         GL_ScissorTest(false);
4859                         R_ClearScreen(r_refdef.fogenabled);
4860                         GL_ScissorTest(true);
4861                         if(r_water_scissormode.integer & 2)
4862                                 R_View_UpdateWithScissor(myscissor);
4863                         else
4864                                 R_View_Update();
4865                         R_AnimCache_CacheVisibleEntities();
4866                         if(r_water_scissormode.integer & 1)
4867                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4868                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4869
4870                         r_fb.water.hideplayer = false;
4871                         p->rt_reflection = rt;
4872                 }
4873
4874                 // render the normal view scene and copy into texture
4875                 // (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)
4876                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
4877                 {
4878                         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);
4879                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4880                                 goto error;
4881                         r_refdef.view = myview;
4882                         if(r_water_scissormode.integer)
4883                         {
4884                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4885                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4886                                 {
4887                                         p->rt_reflection = NULL;
4888                                         p->rt_refraction = NULL;
4889                                         p->rt_camera = NULL;
4890                                         continue;
4891                                 }
4892                         }
4893
4894                         // combined pvs (based on what can be seen from each surface center)
4895                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4896                         {
4897                                 r_refdef.view.usecustompvs = true;
4898                                 if (p->pvsvalid)
4899                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4900                                 else
4901                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4902                         }
4903
4904                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
4905
4906                         r_refdef.view.clipplane = p->plane;
4907                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
4908                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
4909
4910                         if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
4911                         {
4912                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
4913                                 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
4914                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
4915                                 R_RenderView_UpdateViewVectors();
4916                                 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
4917                                 {
4918                                         r_refdef.view.usecustompvs = true;
4919                                         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);
4920                                 }
4921                         }
4922
4923                         PlaneClassify(&r_refdef.view.clipplane);
4924
4925                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4926                         GL_ScissorTest(false);
4927                         R_ClearScreen(r_refdef.fogenabled);
4928                         GL_ScissorTest(true);
4929                         if(r_water_scissormode.integer & 2)
4930                                 R_View_UpdateWithScissor(myscissor);
4931                         else
4932                                 R_View_Update();
4933                         R_AnimCache_CacheVisibleEntities();
4934                         if(r_water_scissormode.integer & 1)
4935                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4936                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4937
4938                         r_fb.water.hideplayer = false;
4939                         p->rt_refraction = rt;
4940                 }
4941                 else if (p->materialflags & MATERIALFLAG_CAMERA)
4942                 {
4943                         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);
4944                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4945                                 goto error;
4946                         r_refdef.view = myview;
4947
4948                         r_refdef.view.clipplane = p->plane;
4949                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
4950                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
4951
4952                         r_refdef.view.width = r_fb.water.camerawidth;
4953                         r_refdef.view.height = r_fb.water.cameraheight;
4954                         r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
4955                         r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
4956                         r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
4957                         r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
4958
4959                         if(p->camera_entity)
4960                         {
4961                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
4962                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
4963                         }
4964
4965                         // note: all of the view is used for displaying... so
4966                         // there is no use in scissoring
4967
4968                         // reverse the cullface settings for this render
4969                         r_refdef.view.cullface_front = GL_FRONT;
4970                         r_refdef.view.cullface_back = GL_BACK;
4971                         // also reverse the view matrix
4972                         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
4973                         R_RenderView_UpdateViewVectors();
4974                         if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
4975                         {
4976                                 r_refdef.view.usecustompvs = true;
4977                                 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);
4978                         }
4979                         
4980                         // camera needs no clipplane
4981                         r_refdef.view.useclipplane = false;
4982                         // TODO: is the camera origin always valid?  if so we don't need to clear this
4983                         r_refdef.view.usevieworiginculling = false;
4984
4985                         PlaneClassify(&r_refdef.view.clipplane);
4986
4987                         r_fb.water.hideplayer = false;
4988
4989                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4990                         GL_ScissorTest(false);
4991                         R_ClearScreen(r_refdef.fogenabled);
4992                         GL_ScissorTest(true);
4993                         R_View_Update();
4994                         R_AnimCache_CacheVisibleEntities();
4995                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4996
4997                         r_fb.water.hideplayer = false;
4998                         p->rt_camera = rt;
4999                 }
5000
5001         }
5002         r_fb.water.renderingscene = false;
5003         r_refdef.view = originalview;
5004         R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5005         R_View_Update();
5006         R_AnimCache_CacheVisibleEntities();
5007         goto finish;
5008 error:
5009         r_refdef.view = originalview;
5010         r_fb.water.renderingscene = false;
5011         Cvar_SetValueQuick(&r_water, 0);
5012         Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed!  Turned off r_water.\n");
5013 finish:
5014         // lowquality hack, restore cvars
5015         if (qualityreduction > 0)
5016         {
5017                 if (qualityreduction >= 1)
5018                 {
5019                         Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5020                         Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5021                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5022                 }
5023                 if (qualityreduction >= 2)
5024                 {
5025                         Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5026                         Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5027                         Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5028                 }
5029         }
5030 }
5031
5032 static void R_Bloom_StartFrame(void)
5033 {
5034         int screentexturewidth, screentextureheight;
5035         textype_t textype = TEXTYPE_COLORBUFFER;
5036         double scale;
5037
5038         // clear the pointers to rendertargets from last frame as they're stale
5039         r_fb.rt_screen = NULL;
5040         r_fb.rt_bloom = NULL;
5041
5042         switch (vid.renderpath)
5043         {
5044         case RENDERPATH_GL32:
5045                 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5046                 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5047                 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5048                 break;
5049         case RENDERPATH_GLES2:
5050                 r_fb.usedepthtextures = false;
5051                 break;
5052         }
5053
5054         if (r_viewscale_fpsscaling.integer)
5055         {
5056                 double actualframetime;
5057                 double targetframetime;
5058                 double adjust;
5059                 actualframetime = r_refdef.lastdrawscreentime;
5060                 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5061                 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5062                 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5063                 if (r_viewscale_fpsscaling_stepsize.value > 0)
5064                 {
5065                         if (adjust > 0)
5066                                 adjust = floor(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5067                         else
5068                                 adjust = ceil(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5069                 }
5070                 viewscalefpsadjusted += adjust;
5071                 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5072         }
5073         else
5074                 viewscalefpsadjusted = 1.0f;
5075
5076         scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
5077         if (vid.samples)
5078                 scale *= sqrt(vid.samples); // supersampling
5079         scale = bound(0.03125f, scale, 4.0f);
5080         screentexturewidth = (int)ceil(r_refdef.view.width * scale);
5081         screentextureheight = (int)ceil(r_refdef.view.height * scale);
5082         screentexturewidth = bound(1, screentexturewidth, (int)vid.maxtexturesize_2d);
5083         screentextureheight = bound(1, screentextureheight, (int)vid.maxtexturesize_2d);
5084
5085         // set bloomwidth and bloomheight to the bloom resolution that will be
5086         // used (often less than the screen resolution for faster rendering)
5087         r_fb.bloomheight = bound(1, r_bloom_resolution.value * 0.75f, vid.height * 4);
5088         r_fb.bloomwidth = r_fb.bloomheight * vid.width / vid.height;
5089         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, vid.width * 4);
5090         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5091         r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
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         if (!r_bloom.integer)
5100                 r_fb.bloomwidth = r_fb.bloomheight = 0;
5101
5102         // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5103         if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5104         {
5105                 if (r_fb.ghosttexture)
5106                         R_FreeTexture(r_fb.ghosttexture);
5107                 r_fb.ghosttexture = NULL;
5108
5109                 r_fb.screentexturewidth = screentexturewidth;
5110                 r_fb.screentextureheight = screentextureheight;
5111                 r_fb.textype = textype;
5112
5113                 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5114                 {
5115                         if (r_motionblur.value > 0 || r_damageblur.value > 0)
5116                                 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);
5117                         r_fb.ghosttexture_valid = false;
5118                 }
5119         }
5120
5121         r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5122
5123         r_refdef.view.clear = true;
5124 }
5125
5126 static void R_Bloom_MakeTexture(void)
5127 {
5128         int x, range, dir;
5129         float xoffset, yoffset, r, brighten;
5130         float colorscale = r_bloom_colorscale.value;
5131         r_viewport_t bloomviewport;
5132         r_rendertarget_t *prev, *cur;
5133         textype_t textype = r_fb.rt_screen->colortextype[0];
5134
5135         r_refdef.stats[r_stat_bloom]++;
5136
5137         R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5138
5139         // scale down screen texture to the bloom texture size
5140         CHECKGLERROR
5141         prev = r_fb.rt_screen;
5142         cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5143         R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5144         R_SetViewport(&bloomviewport);
5145         GL_CullFace(GL_NONE);
5146         GL_DepthTest(false);
5147         GL_BlendFunc(GL_ONE, GL_ZERO);
5148         GL_Color(colorscale, colorscale, colorscale, 1);
5149         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5150         // TODO: do boxfilter scale-down in shader?
5151         R_SetupShader_Generic(prev->colortexture[0], false, true, true);
5152         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5153         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5154         // we now have a properly scaled bloom image
5155
5156         // multiply bloom image by itself as many times as desired to darken it
5157         // TODO: if people actually use this it could be done more quickly in the previous shader pass
5158         for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5159         {
5160                 prev = cur;
5161                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5162                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5163                 x *= 2;
5164                 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5165                 if(x <= 2)
5166                         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0);
5167                 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5168                 GL_Color(1,1,1,1); // no fix factor supported here
5169                 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5170                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5171                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5172                 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5173         }
5174         CHECKGLERROR
5175
5176         range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5177         brighten = r_bloom_brighten.value;
5178         brighten = sqrt(brighten);
5179         if(range >= 1)
5180                 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5181
5182         for (dir = 0;dir < 2;dir++)
5183         {
5184                 prev = cur;
5185                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5186                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5187                 // blend on at multiple vertical offsets to achieve a vertical blur
5188                 // TODO: do offset blends using GLSL
5189                 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5190                 CHECKGLERROR
5191                 GL_BlendFunc(GL_ONE, GL_ZERO);
5192                 CHECKGLERROR
5193                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5194                 CHECKGLERROR
5195                 for (x = -range;x <= range;x++)
5196                 {
5197                         if (!dir){xoffset = 0;yoffset = x;}
5198                         else {xoffset = x;yoffset = 0;}
5199                         xoffset /= (float)prev->texturewidth;
5200                         yoffset /= (float)prev->textureheight;
5201                         // compute a texcoord array with the specified x and y offset
5202                         r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5203                         r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5204                         r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5205                         r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5206                         r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5207                         r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5208                         r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5209                         r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5210                         // this r value looks like a 'dot' particle, fading sharply to
5211                         // black at the edges
5212                         // (probably not realistic but looks good enough)
5213                         //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5214                         //r = brighten/(range*2+1);
5215                         r = brighten / (range * 2 + 1);
5216                         if(range >= 1)
5217                                 r *= (1 - x*x/(float)((range+1)*(range+1)));
5218                         if (r <= 0)
5219                                 continue;
5220                         CHECKGLERROR
5221                         GL_Color(r, r, r, 1);
5222                         CHECKGLERROR
5223                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5224                         CHECKGLERROR
5225                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5226                         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5227                         CHECKGLERROR
5228                         GL_BlendFunc(GL_ONE, GL_ONE);
5229                         CHECKGLERROR
5230                 }
5231         }
5232
5233         // now we have the bloom image, so keep track of it
5234         r_fb.rt_bloom = cur;
5235 }
5236
5237 static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5238 {
5239         dpuint64 permutation;
5240         float uservecs[4][4];
5241         rtexture_t *viewtexture;
5242         rtexture_t *bloomtexture;
5243
5244         R_EntityMatrix(&identitymatrix);
5245
5246         if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
5247         {
5248                 // declare variables
5249                 float blur_factor, blur_mouseaccel, blur_velocity;
5250                 static float blur_average; 
5251                 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5252
5253                 // set a goal for the factoring
5254                 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value) 
5255                         / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5256                 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value) 
5257                         / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5258                 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value) 
5259                         + (blur_mouseaccel * r_motionblur_mousefactor.value));
5260
5261                 // from the goal, pick an averaged value between goal and last value
5262                 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5263                 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5264
5265                 // enforce minimum amount of blur 
5266                 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5267
5268                 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5269
5270                 // calculate values into a standard alpha
5271                 cl.motionbluralpha = 1 - exp(-
5272                                 (
5273                                         (r_motionblur.value * blur_factor / 80)
5274                                         +
5275                                         (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5276                                 )
5277                                 /
5278                                 max(0.0001, cl.time - cl.oldtime) // fps independent
5279                                 );
5280
5281                 // randomization for the blur value to combat persistent ghosting
5282                 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5283                 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5284
5285                 // apply the blur
5286                 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5287                 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5288                 {
5289                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5290                         GL_Color(1, 1, 1, cl.motionbluralpha);
5291                         R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5292                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5293                         R_SetupShader_Generic(r_fb.ghosttexture, false, true, true);
5294                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5295                         r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5296                 }
5297
5298                 // updates old view angles for next pass
5299                 VectorCopy(cl.viewangles, blur_oldangles);
5300
5301                 // copy view into the ghost texture
5302                 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5303                 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5304                 r_fb.ghosttexture_valid = true;
5305         }
5306
5307         if (r_fb.bloomwidth)
5308         {
5309                 // make the bloom texture
5310                 R_Bloom_MakeTexture();
5311         }
5312
5313 #if _MSC_VER >= 1400
5314 #define sscanf sscanf_s
5315 #endif
5316         memset(uservecs, 0, sizeof(uservecs));
5317         if (r_glsl_postprocess_uservec1_enable.integer)
5318                 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5319         if (r_glsl_postprocess_uservec2_enable.integer)
5320                 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5321         if (r_glsl_postprocess_uservec3_enable.integer)
5322                 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5323         if (r_glsl_postprocess_uservec4_enable.integer)
5324                 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5325
5326         // render to the screen fbo
5327         R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5328         GL_Color(1, 1, 1, 1);
5329         GL_BlendFunc(GL_ONE, GL_ZERO);
5330
5331         viewtexture = r_fb.rt_screen->colortexture[0];
5332         bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5333
5334         if (r_rendertarget_debug.integer >= 0)
5335         {
5336                 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5337                 if (rt && rt->colortexture[0])
5338                 {
5339                         viewtexture = rt->colortexture[0];
5340                         bloomtexture = NULL;
5341                 }
5342         }
5343
5344         R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5345         switch(vid.renderpath)
5346         {
5347         case RENDERPATH_GL32:
5348         case RENDERPATH_GLES2:
5349                 permutation =
5350                         (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5351                         | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5352                         | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5353                         | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5354                         | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5355                 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5356                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First     , viewtexture);
5357                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second    , bloomtexture);
5358                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps       );
5359                 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]);
5360                 if (r_glsl_permutation->loc_PixelSize               >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize         , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5361                 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]);
5362                 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]);
5363                 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]);
5364                 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]);
5365                 if (r_glsl_permutation->loc_Saturation              >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation        , r_glsl_saturation.value);
5366                 if (r_glsl_permutation->loc_PixelToScreenTexCoord   >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
5367                 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);
5368                 if (r_glsl_permutation->loc_ColorFringe             >= 0) qglUniform1f(r_glsl_permutation->loc_ColorFringe, r_colorfringe.value );
5369                 break;
5370         }
5371         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5372         r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5373 }
5374
5375 matrix4x4_t r_waterscrollmatrix;
5376
5377 void R_UpdateFog(void)
5378 {
5379         // Nehahra fog
5380         if (gamemode == GAME_NEHAHRA)
5381         {
5382                 if (gl_fogenable.integer)
5383                 {
5384                         r_refdef.oldgl_fogenable = true;
5385                         r_refdef.fog_density = gl_fogdensity.value;
5386                         r_refdef.fog_red = gl_fogred.value;
5387                         r_refdef.fog_green = gl_foggreen.value;
5388                         r_refdef.fog_blue = gl_fogblue.value;
5389                         r_refdef.fog_alpha = 1;
5390                         r_refdef.fog_start = 0;
5391                         r_refdef.fog_end = gl_skyclip.value;
5392                         r_refdef.fog_height = 1<<30;
5393                         r_refdef.fog_fadedepth = 128;
5394                 }
5395                 else if (r_refdef.oldgl_fogenable)
5396                 {
5397                         r_refdef.oldgl_fogenable = false;
5398                         r_refdef.fog_density = 0;
5399                         r_refdef.fog_red = 0;
5400                         r_refdef.fog_green = 0;
5401                         r_refdef.fog_blue = 0;
5402                         r_refdef.fog_alpha = 0;
5403                         r_refdef.fog_start = 0;
5404                         r_refdef.fog_end = 0;
5405                         r_refdef.fog_height = 1<<30;
5406                         r_refdef.fog_fadedepth = 128;
5407                 }
5408         }
5409
5410         // fog parms
5411         r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5412         r_refdef.fog_start = max(0, r_refdef.fog_start);
5413         r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5414
5415         if (r_refdef.fog_density && r_drawfog.integer)
5416         {
5417                 r_refdef.fogenabled = true;
5418                 // this is the point where the fog reaches 0.9986 alpha, which we
5419                 // consider a good enough cutoff point for the texture
5420                 // (0.9986 * 256 == 255.6)
5421                 if (r_fog_exp2.integer)
5422                         r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5423                 else
5424                         r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5425                 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5426                 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5427                 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5428                 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5429                         R_BuildFogHeightTexture();
5430                 // fog color was already set
5431                 // update the fog texture
5432                 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)
5433                         R_BuildFogTexture();
5434                 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5435                 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5436         }
5437         else
5438                 r_refdef.fogenabled = false;
5439
5440         // fog color
5441         if (r_refdef.fog_density)
5442         {
5443                 r_refdef.fogcolor[0] = r_refdef.fog_red;
5444                 r_refdef.fogcolor[1] = r_refdef.fog_green;
5445                 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5446
5447                 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5448                 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5449                 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5450                 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5451
5452                 {
5453                         vec3_t fogvec;
5454                         VectorCopy(r_refdef.fogcolor, fogvec);
5455                         //   color.rgb *= ContrastBoost * SceneBrightness;
5456                         VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5457                         r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5458                         r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5459                         r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5460                 }
5461         }
5462 }
5463
5464 void R_UpdateVariables(void)
5465 {
5466         R_Textures_Frame();
5467
5468         r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5469
5470         r_refdef.farclip = r_farclip_base.value;
5471         if (r_refdef.scene.worldmodel)
5472                 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5473         r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5474
5475         if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5476                 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5477         r_refdef.polygonfactor = 0;
5478         r_refdef.polygonoffset = 0;
5479
5480         r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5481         r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5482         r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5483         r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5484         r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5485         if (r_refdef.scene.worldmodel)
5486         {
5487                 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5488         }
5489         if (r_showsurfaces.integer)
5490         {
5491                 r_refdef.scene.rtworld = false;
5492                 r_refdef.scene.rtworldshadows = false;
5493                 r_refdef.scene.rtdlight = false;
5494                 r_refdef.scene.rtdlightshadows = false;
5495                 r_refdef.scene.lightmapintensity = 0;
5496         }
5497
5498         r_gpuskeletal = false;
5499         switch(vid.renderpath)
5500         {
5501         case RENDERPATH_GL32:
5502                 r_gpuskeletal = r_glsl_skeletal.integer && !r_showsurfaces.integer;
5503         case RENDERPATH_GLES2:
5504                 if(!vid_gammatables_trivial)
5505                 {
5506                         if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5507                         {
5508                                 // build GLSL gamma texture
5509 #define RAMPWIDTH 256
5510                                 unsigned short ramp[RAMPWIDTH * 3];
5511                                 unsigned char rampbgr[RAMPWIDTH][4];
5512                                 int i;
5513
5514                                 r_texture_gammaramps_serial = vid_gammatables_serial;
5515
5516                                 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5517                                 for(i = 0; i < RAMPWIDTH; ++i)
5518                                 {
5519                                         rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5520                                         rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5521                                         rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5522                                         rampbgr[i][3] = 0;
5523                                 }
5524                                 if (r_texture_gammaramps)
5525                                 {
5526                                         R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1);
5527                                 }
5528                                 else
5529                                 {
5530                                         r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5531                                 }
5532                         }
5533                 }
5534                 else
5535                 {
5536                         // remove GLSL gamma texture
5537                 }
5538                 break;
5539         }
5540 }
5541
5542 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5543 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5544 /*
5545 ================
5546 R_SelectScene
5547 ================
5548 */
5549 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5550         if( scenetype != r_currentscenetype ) {
5551                 // store the old scenetype
5552                 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5553                 r_currentscenetype = scenetype;
5554                 // move in the new scene
5555                 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5556         }
5557 }
5558
5559 /*
5560 ================
5561 R_GetScenePointer
5562 ================
5563 */
5564 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5565 {
5566         // of course, we could also add a qboolean that provides a lock state and a ReleaseScenePointer function..
5567         if( scenetype == r_currentscenetype ) {
5568                 return &r_refdef.scene;
5569         } else {
5570                 return &r_scenes_store[ scenetype ];
5571         }
5572 }
5573
5574 static int R_SortEntities_Compare(const void *ap, const void *bp)
5575 {
5576         const entity_render_t *a = *(const entity_render_t **)ap;
5577         const entity_render_t *b = *(const entity_render_t **)bp;
5578
5579         // 1. compare model
5580         if(a->model < b->model)
5581                 return -1;
5582         if(a->model > b->model)
5583                 return +1;
5584
5585         // 2. compare skin
5586         // TODO possibly calculate the REAL skinnum here first using
5587         // skinscenes?
5588         if(a->skinnum < b->skinnum)
5589                 return -1;
5590         if(a->skinnum > b->skinnum)
5591                 return +1;
5592
5593         // everything we compared is equal
5594         return 0;
5595 }
5596 static void R_SortEntities(void)
5597 {
5598         // below or equal 2 ents, sorting never gains anything
5599         if(r_refdef.scene.numentities <= 2)
5600                 return;
5601         // sort
5602         qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5603 }
5604
5605 /*
5606 ================
5607 R_RenderView
5608 ================
5609 */
5610 extern cvar_t r_shadow_bouncegrid;
5611 extern cvar_t v_isometric;
5612 extern void V_MakeViewIsometric(void);
5613 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5614 {
5615         matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5616         int viewfbo = 0;
5617         rtexture_t *viewdepthtexture = NULL;
5618         rtexture_t *viewcolortexture = NULL;
5619         int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5620
5621         // finish any 2D rendering that was queued
5622         DrawQ_Finish();
5623
5624         if (r_timereport_active)
5625                 R_TimeReport("start");
5626         r_textureframe++; // used only by R_GetCurrentTexture
5627         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5628
5629         if(R_CompileShader_CheckStaticParms())
5630                 R_GLSL_Restart_f(&cmd_client);
5631
5632         if (!r_drawentities.integer)
5633                 r_refdef.scene.numentities = 0;
5634         else if (r_sortentities.integer)
5635                 R_SortEntities();
5636
5637         R_AnimCache_ClearCache();
5638
5639         /* adjust for stereo display */
5640         if(R_Stereo_Active())
5641         {
5642                 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);
5643                 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5644         }
5645
5646         if (r_refdef.view.isoverlay)
5647         {
5648                 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5649                 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5650                 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5651                 R_TimeReport("depthclear");
5652
5653                 r_refdef.view.showdebug = false;
5654
5655                 r_fb.water.enabled = false;
5656                 r_fb.water.numwaterplanes = 0;
5657
5658                 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5659
5660                 r_refdef.view.matrix = originalmatrix;
5661
5662                 CHECKGLERROR
5663                 return;
5664         }
5665
5666         if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5667         {
5668                 r_refdef.view.matrix = originalmatrix;
5669                 return;
5670         }
5671
5672         r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5673         if (v_isometric.integer && r_refdef.view.ismain)
5674                 V_MakeViewIsometric();
5675
5676         r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5677
5678         if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5679                 // in sRGB fallback, behave similar to true sRGB: convert this
5680                 // value from linear to sRGB
5681                 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5682
5683         R_RenderView_UpdateViewVectors();
5684
5685         R_Shadow_UpdateWorldLightSelection();
5686
5687         // this will set up r_fb.rt_screen
5688         R_Bloom_StartFrame();
5689
5690         // apply bloom brightness offset
5691         if(r_fb.rt_bloom)
5692                 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5693
5694         // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5695         if (r_fb.rt_screen)
5696         {
5697                 viewfbo = r_fb.rt_screen->fbo;
5698                 viewdepthtexture = r_fb.rt_screen->depthtexture;
5699                 viewcolortexture = r_fb.rt_screen->colortexture[0];
5700                 viewx = 0;
5701                 viewy = 0;
5702                 viewwidth = r_fb.rt_screen->texturewidth;
5703                 viewheight = r_fb.rt_screen->textureheight;
5704         }
5705
5706         R_Water_StartFrame(viewwidth, viewheight);
5707
5708         CHECKGLERROR
5709         if (r_timereport_active)
5710                 R_TimeReport("viewsetup");
5711
5712         R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5713
5714         // clear the whole fbo every frame - otherwise the driver will consider
5715         // it to be an inter-frame texture and stall in multi-gpu configurations
5716         if (r_fb.rt_screen)
5717                 GL_ScissorTest(false);
5718         R_ClearScreen(r_refdef.fogenabled);
5719         if (r_timereport_active)
5720                 R_TimeReport("viewclear");
5721
5722         r_refdef.view.clear = true;
5723
5724         r_refdef.view.showdebug = true;
5725
5726         R_View_Update();
5727         if (r_timereport_active)
5728                 R_TimeReport("visibility");
5729
5730         R_AnimCache_CacheVisibleEntities();
5731         if (r_timereport_active)
5732                 R_TimeReport("animcache");
5733
5734         R_Shadow_UpdateBounceGridTexture();
5735         // R_Shadow_UpdateBounceGridTexture called R_TimeReport a few times internally, so we don't need to do that here.
5736
5737         r_fb.water.numwaterplanes = 0;
5738         if (r_fb.water.enabled)
5739                 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5740
5741         // for the actual view render we use scissoring a fair amount, so scissor
5742         // test needs to be on
5743         if (r_fb.rt_screen)
5744                 GL_ScissorTest(true);
5745         GL_Scissor(viewx, viewy, viewwidth, viewheight);
5746         R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5747         r_fb.water.numwaterplanes = 0;
5748
5749         // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5750         GL_ScissorTest(false);
5751
5752         R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
5753         if (r_timereport_active)
5754                 R_TimeReport("blendview");
5755
5756         r_refdef.view.matrix = originalmatrix;
5757
5758         CHECKGLERROR
5759
5760         // go back to 2d rendering
5761         DrawQ_Start();
5762 }
5763
5764 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5765 {
5766         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5767         {
5768                 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5769                 if (r_timereport_active)
5770                         R_TimeReport("waterworld");
5771         }
5772
5773         // don't let sound skip if going slow
5774         if (r_refdef.scene.extraupdate)
5775                 S_ExtraUpdate ();
5776
5777         R_DrawModelsAddWaterPlanes();
5778         if (r_timereport_active)
5779                 R_TimeReport("watermodels");
5780
5781         if (r_fb.water.numwaterplanes)
5782         {
5783                 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5784                 if (r_timereport_active)
5785                         R_TimeReport("waterscenes");
5786         }
5787 }
5788
5789 extern cvar_t cl_locs_show;
5790 static void R_DrawLocs(void);
5791 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5792 static void R_DrawModelDecals(void);
5793 extern qboolean r_shadow_usingdeferredprepass;
5794 extern int r_shadow_shadowmapatlas_modelshadows_size;
5795 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5796 {
5797         qboolean shadowmapping = false;
5798
5799         if (r_timereport_active)
5800                 R_TimeReport("beginscene");
5801
5802         r_refdef.stats[r_stat_renders]++;
5803
5804         R_UpdateFog();
5805
5806         // don't let sound skip if going slow
5807         if (r_refdef.scene.extraupdate)
5808                 S_ExtraUpdate ();
5809
5810         R_MeshQueue_BeginScene();
5811
5812         R_SkyStartFrame();
5813
5814         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);
5815
5816         if (r_timereport_active)
5817                 R_TimeReport("skystartframe");
5818
5819         if (cl.csqc_vidvars.drawworld)
5820         {
5821                 // don't let sound skip if going slow
5822                 if (r_refdef.scene.extraupdate)
5823                         S_ExtraUpdate ();
5824
5825                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5826                 {
5827                         r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5828                         if (r_timereport_active)
5829                                 R_TimeReport("worldsky");
5830                 }
5831
5832                 if (R_DrawBrushModelsSky() && r_timereport_active)
5833                         R_TimeReport("bmodelsky");
5834
5835                 if (skyrendermasked && skyrenderlater)
5836                 {
5837                         // we have to force off the water clipping plane while rendering sky
5838                         R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5839                         R_Sky();
5840                         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5841                         if (r_timereport_active)
5842                                 R_TimeReport("sky");
5843                 }
5844         }
5845
5846         // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5847         r_shadow_viewfbo = viewfbo;
5848         r_shadow_viewdepthtexture = viewdepthtexture;
5849         r_shadow_viewcolortexture = viewcolortexture;
5850         r_shadow_viewx = viewx;
5851         r_shadow_viewy = viewy;
5852         r_shadow_viewwidth = viewwidth;
5853         r_shadow_viewheight = viewheight;
5854
5855         R_Shadow_PrepareModelShadows();
5856         R_Shadow_PrepareLights();
5857         if (r_timereport_active)
5858                 R_TimeReport("preparelights");
5859
5860         // render all the shadowmaps that will be used for this view
5861         shadowmapping = R_Shadow_ShadowMappingEnabled();
5862         if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
5863         {
5864                 R_Shadow_DrawShadowMaps();
5865                 if (r_timereport_active)
5866                         R_TimeReport("shadowmaps");
5867         }
5868
5869         // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
5870         if (r_shadow_usingdeferredprepass)
5871                 R_Shadow_DrawPrepass();
5872
5873         // now we begin the forward pass of the view render
5874         if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
5875         {
5876                 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
5877                 if (r_timereport_active)
5878                         R_TimeReport("worlddepth");
5879         }
5880         if (r_depthfirst.integer >= 2)
5881         {
5882                 R_DrawModelsDepth();
5883                 if (r_timereport_active)
5884                         R_TimeReport("modeldepth");
5885         }
5886
5887         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
5888         {
5889                 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
5890                 if (r_timereport_active)
5891                         R_TimeReport("world");
5892         }
5893
5894         // don't let sound skip if going slow
5895         if (r_refdef.scene.extraupdate)
5896                 S_ExtraUpdate ();
5897
5898         R_DrawModels();
5899         if (r_timereport_active)
5900                 R_TimeReport("models");
5901
5902         // don't let sound skip if going slow
5903         if (r_refdef.scene.extraupdate)
5904                 S_ExtraUpdate ();
5905
5906         if (!r_shadow_usingdeferredprepass)
5907         {
5908                 R_Shadow_DrawLights();
5909                 if (r_timereport_active)
5910                         R_TimeReport("rtlights");
5911         }
5912
5913         // don't let sound skip if going slow
5914         if (r_refdef.scene.extraupdate)
5915                 S_ExtraUpdate ();
5916
5917         if (cl.csqc_vidvars.drawworld)
5918         {
5919                 R_DrawModelDecals();
5920                 if (r_timereport_active)
5921                         R_TimeReport("modeldecals");
5922
5923                 R_DrawParticles();
5924                 if (r_timereport_active)
5925                         R_TimeReport("particles");
5926
5927                 R_DrawExplosions();
5928                 if (r_timereport_active)
5929                         R_TimeReport("explosions");
5930         }
5931
5932         if (r_refdef.view.showdebug)
5933         {
5934                 if (cl_locs_show.integer)
5935                 {
5936                         R_DrawLocs();
5937                         if (r_timereport_active)
5938                                 R_TimeReport("showlocs");
5939                 }
5940
5941                 if (r_drawportals.integer)
5942                 {
5943                         R_DrawPortals();
5944                         if (r_timereport_active)
5945                                 R_TimeReport("portals");
5946                 }
5947
5948                 if (r_showbboxes_client.value > 0)
5949                 {
5950                         R_DrawEntityBBoxes(CLVM_prog);
5951                         if (r_timereport_active)
5952                                 R_TimeReport("clbboxes");
5953                 }
5954                 if (r_showbboxes.value > 0)
5955                 {
5956                         R_DrawEntityBBoxes(SVVM_prog);
5957                         if (r_timereport_active)
5958                                 R_TimeReport("svbboxes");
5959                 }
5960         }
5961
5962         if (r_transparent.integer)
5963         {
5964                 R_MeshQueue_RenderTransparent();
5965                 if (r_timereport_active)
5966                         R_TimeReport("drawtrans");
5967         }
5968
5969         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))
5970         {
5971                 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
5972                 if (r_timereport_active)
5973                         R_TimeReport("worlddebug");
5974                 R_DrawModelsDebug();
5975                 if (r_timereport_active)
5976                         R_TimeReport("modeldebug");
5977         }
5978
5979         if (cl.csqc_vidvars.drawworld)
5980         {
5981                 R_Shadow_DrawCoronas();
5982                 if (r_timereport_active)
5983                         R_TimeReport("coronas");
5984         }
5985
5986         // don't let sound skip if going slow
5987         if (r_refdef.scene.extraupdate)
5988                 S_ExtraUpdate ();
5989 }
5990
5991 static const unsigned short bboxelements[36] =
5992 {
5993         5, 1, 3, 5, 3, 7,
5994         6, 2, 0, 6, 0, 4,
5995         7, 3, 2, 7, 2, 6,
5996         4, 0, 1, 4, 1, 5,
5997         4, 5, 7, 4, 7, 6,
5998         1, 0, 2, 1, 2, 3,
5999 };
6000
6001 #define BBOXEDGES 13
6002 static const float bboxedges[BBOXEDGES][6] = 
6003 {
6004         // whole box
6005         { 0, 0, 0, 1, 1, 1 },
6006         // bottom edges
6007         { 0, 0, 0, 0, 1, 0 },
6008         { 0, 0, 0, 1, 0, 0 },
6009         { 0, 1, 0, 1, 1, 0 },
6010         { 1, 0, 0, 1, 1, 0 },
6011         // top edges
6012         { 0, 0, 1, 0, 1, 1 },
6013         { 0, 0, 1, 1, 0, 1 },
6014         { 0, 1, 1, 1, 1, 1 },
6015         { 1, 0, 1, 1, 1, 1 },
6016         // vertical edges
6017         { 0, 0, 0, 0, 0, 1 },
6018         { 1, 0, 0, 1, 0, 1 },
6019         { 0, 1, 0, 0, 1, 1 },
6020         { 1, 1, 0, 1, 1, 1 },
6021 };
6022
6023 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6024 {
6025         int numvertices = BBOXEDGES * 8;
6026         float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6027         int numtriangles = BBOXEDGES * 12;
6028         unsigned short elements[BBOXEDGES * 36];
6029         int i, edge;
6030         float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6031
6032         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6033
6034         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6035         GL_DepthMask(false);
6036         GL_DepthRange(0, 1);
6037         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6038
6039         for (edge = 0; edge < BBOXEDGES; edge++)
6040         {
6041                 for (i = 0; i < 3; i++)
6042                 {
6043                         edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6044                         edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6045                 }
6046                 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6047                 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6048                 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6049                 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6050                 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6051                 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6052                 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6053                 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6054                 for (i = 0; i < 36; i++)
6055                         elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6056         }
6057         R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6058         if (r_refdef.fogenabled)
6059         {
6060                 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6061                 {
6062                         f1 = RSurf_FogVertex(v);
6063                         f2 = 1 - f1;
6064                         c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6065                         c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6066                         c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6067                 }
6068         }
6069         R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6070         R_Mesh_ResetTextureState();
6071         R_SetupShader_Generic_NoTexture(false, false);
6072         R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6073 }
6074
6075 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6076 {
6077         // hacky overloading of the parameters
6078         prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6079         int i;
6080         float color[4];
6081         prvm_edict_t *edict;
6082
6083         GL_CullFace(GL_NONE);
6084         R_SetupShader_Generic_NoTexture(false, false);
6085
6086         for (i = 0;i < numsurfaces;i++)
6087         {
6088                 edict = PRVM_EDICT_NUM(surfacelist[i]);
6089                 switch ((int)PRVM_serveredictfloat(edict, solid))
6090                 {
6091                         case SOLID_NOT:      Vector4Set(color, 1, 1, 1, 0.05);break;
6092                         case SOLID_TRIGGER:  Vector4Set(color, 1, 0, 1, 0.10);break;
6093                         case SOLID_BBOX:     Vector4Set(color, 0, 1, 0, 0.10);break;
6094                         case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6095                         case SOLID_BSP:      Vector4Set(color, 0, 0, 1, 0.05);break;
6096                         case SOLID_CORPSE:   Vector4Set(color, 1, 0.5, 0, 0.05);break;
6097                         default:             Vector4Set(color, 0, 0, 0, 0.50);break;
6098                 }
6099                 if (prog == CLVM_prog)
6100                         color[3] *= r_showbboxes_client.value;
6101                 else
6102                         color[3] *= r_showbboxes.value;
6103                 color[3] = bound(0, color[3], 1);
6104                 GL_DepthTest(!r_showdisabledepthtest.integer);
6105                 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6106         }
6107 }
6108
6109 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6110 {
6111         int i;
6112         prvm_edict_t *edict;
6113         vec3_t center;
6114
6115         if (prog == NULL)
6116                 return;
6117
6118         for (i = 0; i < prog->num_edicts; i++)
6119         {
6120                 edict = PRVM_EDICT_NUM(i);
6121                 if (edict->priv.server->free)
6122                         continue;
6123                 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6124                 if (PRVM_gameedictedict(edict, tag_entity) != 0)
6125                         continue;
6126                 if (prog == SVVM_prog && PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6127                         continue;
6128                 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6129                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6130         }
6131 }
6132
6133 static const int nomodelelement3i[24] =
6134 {
6135         5, 2, 0,
6136         5, 1, 2,
6137         5, 0, 3,
6138         5, 3, 1,
6139         0, 2, 4,
6140         2, 1, 4,
6141         3, 0, 4,
6142         1, 3, 4
6143 };
6144
6145 static const unsigned short nomodelelement3s[24] =
6146 {
6147         5, 2, 0,
6148         5, 1, 2,
6149         5, 0, 3,
6150         5, 3, 1,
6151         0, 2, 4,
6152         2, 1, 4,
6153         3, 0, 4,
6154         1, 3, 4
6155 };
6156
6157 static const float nomodelvertex3f[6*3] =
6158 {
6159         -16,   0,   0,
6160          16,   0,   0,
6161           0, -16,   0,
6162           0,  16,   0,
6163           0,   0, -16,
6164           0,   0,  16
6165 };
6166
6167 static const float nomodelcolor4f[6*4] =
6168 {
6169         0.0f, 0.0f, 0.5f, 1.0f,
6170         0.0f, 0.0f, 0.5f, 1.0f,
6171         0.0f, 0.5f, 0.0f, 1.0f,
6172         0.0f, 0.5f, 0.0f, 1.0f,
6173         0.5f, 0.0f, 0.0f, 1.0f,
6174         0.5f, 0.0f, 0.0f, 1.0f
6175 };
6176
6177 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6178 {
6179         int i;
6180         float f1, f2, *c;
6181         float color4f[6*4];
6182
6183         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);
6184
6185         // this is only called once per entity so numsurfaces is always 1, and
6186         // surfacelist is always {0}, so this code does not handle batches
6187
6188         if (rsurface.ent_flags & RENDER_ADDITIVE)
6189         {
6190                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6191                 GL_DepthMask(false);
6192         }
6193         else if (ent->alpha < 1)
6194         {
6195                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6196                 GL_DepthMask(false);
6197         }
6198         else
6199         {
6200                 GL_BlendFunc(GL_ONE, GL_ZERO);
6201                 GL_DepthMask(true);
6202         }
6203         GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6204         GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6205         GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6206         GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6207         memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6208         for (i = 0, c = color4f;i < 6;i++, c += 4)
6209         {
6210                 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6211                 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6212                 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6213                 c[3] *= ent->alpha;
6214         }
6215         if (r_refdef.fogenabled)
6216         {
6217                 for (i = 0, c = color4f;i < 6;i++, c += 4)
6218                 {
6219                         f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6220                         f2 = 1 - f1;
6221                         c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6222                         c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6223                         c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6224                 }
6225         }
6226 //      R_Mesh_ResetTextureState();
6227         R_SetupShader_Generic_NoTexture(false, false);
6228         R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6229         R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6230 }
6231
6232 void R_DrawNoModel(entity_render_t *ent)
6233 {
6234         vec3_t org;
6235         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6236         if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6237                 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6238         else
6239                 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6240 }
6241
6242 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6243 {
6244         vec3_t right1, right2, diff, normal;
6245
6246         VectorSubtract (org2, org1, normal);
6247
6248         // calculate 'right' vector for start
6249         VectorSubtract (r_refdef.view.origin, org1, diff);
6250         CrossProduct (normal, diff, right1);
6251         VectorNormalize (right1);
6252
6253         // calculate 'right' vector for end
6254         VectorSubtract (r_refdef.view.origin, org2, diff);
6255         CrossProduct (normal, diff, right2);
6256         VectorNormalize (right2);
6257
6258         vert[ 0] = org1[0] + width * right1[0];
6259         vert[ 1] = org1[1] + width * right1[1];
6260         vert[ 2] = org1[2] + width * right1[2];
6261         vert[ 3] = org1[0] - width * right1[0];
6262         vert[ 4] = org1[1] - width * right1[1];
6263         vert[ 5] = org1[2] - width * right1[2];
6264         vert[ 6] = org2[0] - width * right2[0];
6265         vert[ 7] = org2[1] - width * right2[1];
6266         vert[ 8] = org2[2] - width * right2[2];
6267         vert[ 9] = org2[0] + width * right2[0];
6268         vert[10] = org2[1] + width * right2[1];
6269         vert[11] = org2[2] + width * right2[2];
6270 }
6271
6272 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)
6273 {
6274         vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6275         vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6276         vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6277         vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6278         vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6279         vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6280         vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6281         vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6282         vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6283         vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6284         vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6285         vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6286 }
6287
6288 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6289 {
6290         int i;
6291         float *vertex3f;
6292         float v[3];
6293         VectorSet(v, x, y, z);
6294         for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6295                 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6296                         break;
6297         if (i == mesh->numvertices)
6298         {
6299                 if (mesh->numvertices < mesh->maxvertices)
6300                 {
6301                         VectorCopy(v, vertex3f);
6302                         mesh->numvertices++;
6303                 }
6304                 return mesh->numvertices;
6305         }
6306         else
6307                 return i;
6308 }
6309
6310 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6311 {
6312         int i;
6313         int *e, element[3];
6314         element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6315         element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6316         e = mesh->element3i + mesh->numtriangles * 3;
6317         for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6318         {
6319                 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6320                 if (mesh->numtriangles < mesh->maxtriangles)
6321                 {
6322                         *e++ = element[0];
6323                         *e++ = element[1];
6324                         *e++ = element[2];
6325                         mesh->numtriangles++;
6326                 }
6327                 element[1] = element[2];
6328         }
6329 }
6330
6331 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6332 {
6333         int i;
6334         int *e, element[3];
6335         element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6336         element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6337         e = mesh->element3i + mesh->numtriangles * 3;
6338         for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6339         {
6340                 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6341                 if (mesh->numtriangles < mesh->maxtriangles)
6342                 {
6343                         *e++ = element[0];
6344                         *e++ = element[1];
6345                         *e++ = element[2];
6346                         mesh->numtriangles++;
6347                 }
6348                 element[1] = element[2];
6349         }
6350 }
6351
6352 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6353 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6354 {
6355         int planenum, planenum2;
6356         int w;
6357         int tempnumpoints;
6358         mplane_t *plane, *plane2;
6359         double maxdist;
6360         double temppoints[2][256*3];
6361         // figure out how large a bounding box we need to properly compute this brush
6362         maxdist = 0;
6363         for (w = 0;w < numplanes;w++)
6364                 maxdist = max(maxdist, fabs(planes[w].dist));
6365         // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6366         maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6367         for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6368         {
6369                 w = 0;
6370                 tempnumpoints = 4;
6371                 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6372                 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6373                 {
6374                         if (planenum2 == planenum)
6375                                 continue;
6376                         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);
6377                         w = !w;
6378                 }
6379                 if (tempnumpoints < 3)
6380                         continue;
6381                 // generate elements forming a triangle fan for this polygon
6382                 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6383         }
6384 }
6385
6386 static qboolean R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6387 {
6388         if(parms[0] == 0 && parms[1] == 0)
6389                 return false;
6390         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6391                 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6392                         return false;
6393         return true;
6394 }
6395
6396 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6397 {
6398         double index, f;
6399         index = parms[2] + rsurface.shadertime * parms[3];
6400         index -= floor(index);
6401         switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6402         {
6403         default:
6404         case Q3WAVEFUNC_NONE:
6405         case Q3WAVEFUNC_NOISE:
6406         case Q3WAVEFUNC_COUNT:
6407                 f = 0;
6408                 break;
6409         case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6410         case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6411         case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6412         case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6413         case Q3WAVEFUNC_TRIANGLE:
6414                 index *= 4;
6415                 f = index - floor(index);
6416                 if (index < 1)
6417                 {
6418                         // f = f;
6419                 }
6420                 else if (index < 2)
6421                         f = 1 - f;
6422                 else if (index < 3)
6423                         f = -f;
6424                 else
6425                         f = -(1 - f);
6426                 break;
6427         }
6428         f = parms[0] + parms[1] * f;
6429         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6430                 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6431         return (float) f;
6432 }
6433
6434 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6435 {
6436         int w, h, idx;
6437         float shadertime;
6438         float f;
6439         float offsetd[2];
6440         float tcmat[12];
6441         matrix4x4_t matrix, temp;
6442         // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6443         // it's better to have one huge fixup every 9 hours than gradual
6444         // degradation over time which looks consistently bad after many hours.
6445         //
6446         // tcmod scroll in particular suffers from this degradation which can't be
6447         // effectively worked around even with floor() tricks because we don't
6448         // know if tcmod scroll is the last tcmod being applied, and for clampmap
6449         // a workaround involving floor() would be incorrect anyway...
6450         shadertime = rsurface.shadertime;
6451         if (shadertime >= 32768.0f)
6452                 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6453         switch(tcmod->tcmod)
6454         {
6455                 case Q3TCMOD_COUNT:
6456                 case Q3TCMOD_NONE:
6457                         if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6458                                 matrix = r_waterscrollmatrix;
6459                         else
6460                                 matrix = identitymatrix;
6461                         break;
6462                 case Q3TCMOD_ENTITYTRANSLATE:
6463                         // this is used in Q3 to allow the gamecode to control texcoord
6464                         // scrolling on the entity, which is not supported in darkplaces yet.
6465                         Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6466                         break;
6467                 case Q3TCMOD_ROTATE:
6468                         Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6469                         Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6470                         Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6471                         break;
6472                 case Q3TCMOD_SCALE:
6473                         Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6474                         break;
6475                 case Q3TCMOD_SCROLL:
6476                         // this particular tcmod is a "bug for bug" compatible one with regards to
6477                         // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6478                         // specifically did the wrapping and so we must mimic that...
6479                         offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6480                         offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6481                         Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6482                         break;
6483                 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6484                         w = (int) tcmod->parms[0];
6485                         h = (int) tcmod->parms[1];
6486                         f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6487                         f = f - floor(f);
6488                         idx = (int) floor(f * w * h);
6489                         Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6490                         break;
6491                 case Q3TCMOD_STRETCH:
6492                         f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6493                         Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6494                         break;
6495                 case Q3TCMOD_TRANSFORM:
6496                         VectorSet(tcmat +  0, tcmod->parms[0], tcmod->parms[1], 0);
6497                         VectorSet(tcmat +  3, tcmod->parms[2], tcmod->parms[3], 0);
6498                         VectorSet(tcmat +  6, 0                   , 0                , 1);
6499                         VectorSet(tcmat +  9, tcmod->parms[4], tcmod->parms[5], 0);
6500                         Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6501                         break;
6502                 case Q3TCMOD_TURBULENT:
6503                         // this is handled in the RSurf_PrepareVertices function
6504                         matrix = identitymatrix;
6505                         break;
6506         }
6507         temp = *texmatrix;
6508         Matrix4x4_Concat(texmatrix, &matrix, &temp);
6509 }
6510
6511 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6512 {
6513         int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6514         char name[MAX_QPATH];
6515         skinframe_t *skinframe;
6516         unsigned char pixels[296*194];
6517         strlcpy(cache->name, skinname, sizeof(cache->name));
6518         dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6519         if (developer_loading.integer)
6520                 Con_Printf("loading %s\n", name);
6521         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6522         if (!skinframe || !skinframe->base)
6523         {
6524                 unsigned char *f;
6525                 fs_offset_t filesize;
6526                 skinframe = NULL;
6527                 f = FS_LoadFile(name, tempmempool, true, &filesize);
6528                 if (f)
6529                 {
6530                         if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6531                                 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6532                         Mem_Free(f);
6533                 }
6534         }
6535         cache->skinframe = skinframe;
6536 }
6537
6538 texture_t *R_GetCurrentTexture(texture_t *t)
6539 {
6540         int i, q;
6541         const entity_render_t *ent = rsurface.entity;
6542         dp_model_t *model = ent->model; // when calling this, ent must not be NULL
6543         q3shaderinfo_layer_tcmod_t *tcmod;
6544         float specularscale = 0.0f;
6545
6546         if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6547                 return t->currentframe;
6548         t->update_lastrenderframe = r_textureframe;
6549         t->update_lastrenderentity = (void *)ent;
6550
6551         if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6552                 t->camera_entity = ent->entitynumber;
6553         else
6554                 t->camera_entity = 0;
6555
6556         // switch to an alternate material if this is a q1bsp animated material
6557         {
6558                 texture_t *texture = t;
6559                 int s = rsurface.ent_skinnum;
6560                 if ((unsigned int)s >= (unsigned int)model->numskins)
6561                         s = 0;
6562                 if (model->skinscenes)
6563                 {
6564                         if (model->skinscenes[s].framecount > 1)
6565                                 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6566                         else
6567                                 s = model->skinscenes[s].firstframe;
6568                 }
6569                 if (s > 0)
6570                         t = t + s * model->num_surfaces;
6571                 if (t->animated)
6572                 {
6573                         // use an alternate animation if the entity's frame is not 0,
6574                         // and only if the texture has an alternate animation
6575                         if (t->animated == 2) // q2bsp
6576                                 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6577                         else if (rsurface.ent_alttextures && t->anim_total[1])
6578                                 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6579                         else
6580                                 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6581                 }
6582                 texture->currentframe = t;
6583         }
6584
6585         // update currentskinframe to be a qw skin or animation frame
6586         if (rsurface.ent_qwskin >= 0)
6587         {
6588                 i = rsurface.ent_qwskin;
6589                 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6590                 {
6591                         r_qwskincache_size = cl.maxclients;
6592                         if (r_qwskincache)
6593                                 Mem_Free(r_qwskincache);
6594                         r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6595                 }
6596                 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6597                         R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6598                 t->currentskinframe = r_qwskincache[i].skinframe;
6599                 if (t->materialshaderpass && t->currentskinframe == NULL)
6600                         t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6601         }
6602         else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6603                 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6604         if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6605                 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6606
6607         t->currentmaterialflags = t->basematerialflags;
6608         t->currentalpha = rsurface.entity->alpha * t->basealpha;
6609         if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_water.integer || r_novis.integer || r_trippy.integer))
6610                 t->currentalpha *= r_wateralpha.value;
6611         if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6612                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6613         if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6614                 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6615
6616         // decide on which type of lighting to use for this surface
6617         if (rsurface.entity->render_modellight_forced)
6618                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6619         if (rsurface.entity->render_rtlight_disabled)
6620                 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6621         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6622         {
6623                 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6624                 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NORTLIGHT;
6625                 for (q = 0; q < 3; q++)
6626                 {
6627                         t->render_glowmod[q] = rsurface.entity->glowmod[q];
6628                         t->render_modellight_lightdir[q] = q == 2;
6629                         t->render_modellight_ambient[q] = 1;
6630                         t->render_modellight_diffuse[q] = 0;
6631                         t->render_modellight_specular[q] = 0;
6632                         t->render_lightmap_ambient[q] = 0;
6633                         t->render_lightmap_diffuse[q] = 0;
6634                         t->render_lightmap_specular[q] = 0;
6635                         t->render_rtlight_diffuse[q] = 0;
6636                         t->render_rtlight_specular[q] = 0;
6637                 }
6638         }
6639         else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6640         {
6641                 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6642                 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT;
6643                 for (q = 0; q < 3; q++)
6644                 {
6645                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6646                         t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6647                         t->render_modellight_lightdir[q] = q == 2;
6648                         t->render_modellight_diffuse[q] = 0;
6649                         t->render_modellight_specular[q] = 0;
6650                         t->render_lightmap_ambient[q] = 0;
6651                         t->render_lightmap_diffuse[q] = 0;
6652                         t->render_lightmap_specular[q] = 0;
6653                         t->render_rtlight_diffuse[q] = 0;
6654                         t->render_rtlight_specular[q] = 0;
6655                 }
6656         }
6657         else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6658         {
6659                 // ambient + single direction light (modellight)
6660                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6661                 for (q = 0; q < 3; q++)
6662                 {
6663                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6664                         t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6665                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6666                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6667                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6668                         t->render_lightmap_ambient[q] = 0;
6669                         t->render_lightmap_diffuse[q] = 0;
6670                         t->render_lightmap_specular[q] = 0;
6671                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6672                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6673                 }
6674         }
6675         else
6676         {
6677                 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6678                 for (q = 0; q < 3; q++)
6679                 {
6680                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6681                         t->render_modellight_lightdir[q] = q == 2;
6682                         t->render_modellight_ambient[q] = 0;
6683                         t->render_modellight_diffuse[q] = 0;
6684                         t->render_modellight_specular[q] = 0;
6685                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6686                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6687                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6688                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6689                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6690                 }
6691         }
6692
6693         if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6694         {
6695                 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6696                 // attribute, we punt it to the lightmap path and hope for the best,
6697                 // but lighting doesn't work.
6698                 //
6699                 // FIXME: this is fine for effects but CSQC polygons should be subject
6700                 // to lighting.
6701                 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6702                 for (q = 0; q < 3; q++)
6703                 {
6704                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6705                         t->render_modellight_lightdir[q] = q == 2;
6706                         t->render_modellight_ambient[q] = 0;
6707                         t->render_modellight_diffuse[q] = 0;
6708                         t->render_modellight_specular[q] = 0;
6709                         t->render_lightmap_ambient[q] = 0;
6710                         t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6711                         t->render_lightmap_specular[q] = 0;
6712                         t->render_rtlight_diffuse[q] = 0;
6713                         t->render_rtlight_specular[q] = 0;
6714                 }
6715         }
6716
6717         for (q = 0; q < 3; q++)
6718         {
6719                 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6720                 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6721         }
6722
6723         if (rsurface.ent_flags & RENDER_ADDITIVE)
6724                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6725         else if (t->currentalpha < 1)
6726                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6727         // LadyHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6728         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6729                 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6730         if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6731                 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6732         if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6733                 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6734         if (t->backgroundshaderpass)
6735                 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6736         if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6737         {
6738                 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6739                         t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6740         }
6741         else
6742                 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6743         if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6744         {
6745                 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6746                 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6747         }
6748         if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6749                 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6750
6751         // there is no tcmod
6752         if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6753         {
6754                 t->currenttexmatrix = r_waterscrollmatrix;
6755                 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6756         }
6757         else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6758         {
6759                 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6760                 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6761         }
6762
6763         if (t->materialshaderpass)
6764                 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6765                         R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6766
6767         t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6768         if (t->currentskinframe->qpixels)
6769                 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6770         t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6771         if (!t->basetexture)
6772                 t->basetexture = r_texture_notexture;
6773         t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6774         t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6775         t->nmaptexture = t->currentskinframe->nmap;
6776         if (!t->nmaptexture)
6777                 t->nmaptexture = r_texture_blanknormalmap;
6778         t->glosstexture = r_texture_black;
6779         t->glowtexture = t->currentskinframe->glow;
6780         t->fogtexture = t->currentskinframe->fog;
6781         t->reflectmasktexture = t->currentskinframe->reflect;
6782         if (t->backgroundshaderpass)
6783         {
6784                 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6785                         R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6786                 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6787                 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6788                 t->backgroundglosstexture = r_texture_black;
6789                 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6790                 if (!t->backgroundnmaptexture)
6791                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6792                 // make sure that if glow is going to be used, both textures are not NULL
6793                 if (!t->backgroundglowtexture && t->glowtexture)
6794                         t->backgroundglowtexture = r_texture_black;
6795                 if (!t->glowtexture && t->backgroundglowtexture)
6796                         t->glowtexture = r_texture_black;
6797         }
6798         else
6799         {
6800                 t->backgroundbasetexture = r_texture_white;
6801                 t->backgroundnmaptexture = r_texture_blanknormalmap;
6802                 t->backgroundglosstexture = r_texture_black;
6803                 t->backgroundglowtexture = NULL;
6804         }
6805         t->specularpower = r_shadow_glossexponent.value;
6806         // TODO: store reference values for these in the texture?
6807         if (r_shadow_gloss.integer > 0)
6808         {
6809                 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
6810                 {
6811                         if (r_shadow_glossintensity.value > 0)
6812                         {
6813                                 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
6814                                 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
6815                                 specularscale = r_shadow_glossintensity.value;
6816                         }
6817                 }
6818                 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
6819                 {
6820                         t->glosstexture = r_texture_white;
6821                         t->backgroundglosstexture = r_texture_white;
6822                         specularscale = r_shadow_gloss2intensity.value;
6823                         t->specularpower = r_shadow_gloss2exponent.value;
6824                 }
6825         }
6826         specularscale *= t->specularscalemod;
6827         t->specularpower *= t->specularpowermod;
6828
6829         // lightmaps mode looks bad with dlights using actual texturing, so turn
6830         // off the colormap and glossmap, but leave the normalmap on as it still
6831         // accurately represents the shading involved
6832         if (gl_lightmaps.integer)
6833         {
6834                 t->basetexture = r_texture_grey128;
6835                 t->pantstexture = r_texture_black;
6836                 t->shirttexture = r_texture_black;
6837                 if (gl_lightmaps.integer < 2)
6838                         t->nmaptexture = r_texture_blanknormalmap;
6839                 t->glosstexture = r_texture_black;
6840                 t->glowtexture = NULL;
6841                 t->fogtexture = NULL;
6842                 t->reflectmasktexture = NULL;
6843                 t->backgroundbasetexture = NULL;
6844                 if (gl_lightmaps.integer < 2)
6845                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6846                 t->backgroundglosstexture = r_texture_black;
6847                 t->backgroundglowtexture = NULL;
6848                 specularscale = 0;
6849                 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
6850         }
6851
6852         if (specularscale != 1.0f)
6853         {
6854                 for (q = 0; q < 3; q++)
6855                 {
6856                         t->render_modellight_specular[q] *= specularscale;
6857                         t->render_lightmap_specular[q] *= specularscale;
6858                         t->render_rtlight_specular[q] *= specularscale;
6859                 }
6860         }
6861
6862         t->currentblendfunc[0] = GL_ONE;
6863         t->currentblendfunc[1] = GL_ZERO;
6864         if (t->currentmaterialflags & MATERIALFLAG_ADD)
6865         {
6866                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6867                 t->currentblendfunc[1] = GL_ONE;
6868         }
6869         else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
6870         {
6871                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6872                 t->currentblendfunc[1] = GL_ONE_MINUS_SRC_ALPHA;
6873         }
6874         else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6875         {
6876                 t->currentblendfunc[0] = t->customblendfunc[0];
6877                 t->currentblendfunc[1] = t->customblendfunc[1];
6878         }
6879
6880         return t;
6881 }
6882
6883 rsurfacestate_t rsurface;
6884
6885 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
6886 {
6887         dp_model_t *model = ent->model;
6888         //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
6889         //      return;
6890         rsurface.entity = (entity_render_t *)ent;
6891         rsurface.skeleton = ent->skeleton;
6892         memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
6893         rsurface.ent_skinnum = ent->skinnum;
6894         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;
6895         rsurface.ent_flags = ent->flags;
6896         if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
6897                 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
6898         rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
6899         rsurface.matrix = ent->matrix;
6900         rsurface.inversematrix = ent->inversematrix;
6901         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
6902         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
6903         R_EntityMatrix(&rsurface.matrix);
6904         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
6905         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
6906         rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
6907         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
6908         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
6909         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
6910         memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
6911         rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
6912         rsurface.basepolygonfactor = r_refdef.polygonfactor;
6913         rsurface.basepolygonoffset = r_refdef.polygonoffset;
6914         if (ent->model->brush.submodel && !prepass)
6915         {
6916                 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
6917                 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
6918         }
6919         // if the animcache code decided it should use the shader path, skip the deform step
6920         rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
6921         rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
6922         rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
6923         rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
6924         rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
6925         if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
6926         {
6927                 if (ent->animcache_vertex3f)
6928                 {
6929                         r_refdef.stats[r_stat_batch_entitycache_count]++;
6930                         r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
6931                         r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
6932                         r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
6933                         rsurface.modelvertex3f = ent->animcache_vertex3f;
6934                         rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
6935                         rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
6936                         rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
6937                         rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
6938                         rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
6939                         rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
6940                         rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
6941                         rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
6942                         rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
6943                         rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
6944                         rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
6945                 }
6946                 else if (wanttangents)
6947                 {
6948                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
6949                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
6950                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
6951                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
6952                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6953                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6954                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6955                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6956                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
6957                         rsurface.modelvertex3f_vertexbuffer = NULL;
6958                         rsurface.modelvertex3f_bufferoffset = 0;
6959                         rsurface.modelvertex3f_vertexbuffer = 0;
6960                         rsurface.modelvertex3f_bufferoffset = 0;
6961                         rsurface.modelsvector3f_vertexbuffer = 0;
6962                         rsurface.modelsvector3f_bufferoffset = 0;
6963                         rsurface.modeltvector3f_vertexbuffer = 0;
6964                         rsurface.modeltvector3f_bufferoffset = 0;
6965                         rsurface.modelnormal3f_vertexbuffer = 0;
6966                         rsurface.modelnormal3f_bufferoffset = 0;
6967                 }
6968                 else if (wantnormals)
6969                 {
6970                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
6971                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
6972                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
6973                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
6974                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6975                         rsurface.modelsvector3f = NULL;
6976                         rsurface.modeltvector3f = NULL;
6977                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6978                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
6979                         rsurface.modelvertex3f_vertexbuffer = NULL;
6980                         rsurface.modelvertex3f_bufferoffset = 0;
6981                         rsurface.modelvertex3f_vertexbuffer = 0;
6982                         rsurface.modelvertex3f_bufferoffset = 0;
6983                         rsurface.modelsvector3f_vertexbuffer = 0;
6984                         rsurface.modelsvector3f_bufferoffset = 0;
6985                         rsurface.modeltvector3f_vertexbuffer = 0;
6986                         rsurface.modeltvector3f_bufferoffset = 0;
6987                         rsurface.modelnormal3f_vertexbuffer = 0;
6988                         rsurface.modelnormal3f_bufferoffset = 0;
6989                 }
6990                 else
6991                 {
6992                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
6993                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
6994                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
6995                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
6996                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6997                         rsurface.modelsvector3f = NULL;
6998                         rsurface.modeltvector3f = NULL;
6999                         rsurface.modelnormal3f = NULL;
7000                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7001                         rsurface.modelvertex3f_vertexbuffer = NULL;
7002                         rsurface.modelvertex3f_bufferoffset = 0;
7003                         rsurface.modelvertex3f_vertexbuffer = 0;
7004                         rsurface.modelvertex3f_bufferoffset = 0;
7005                         rsurface.modelsvector3f_vertexbuffer = 0;
7006                         rsurface.modelsvector3f_bufferoffset = 0;
7007                         rsurface.modeltvector3f_vertexbuffer = 0;
7008                         rsurface.modeltvector3f_bufferoffset = 0;
7009                         rsurface.modelnormal3f_vertexbuffer = 0;
7010                         rsurface.modelnormal3f_bufferoffset = 0;
7011                 }
7012                 rsurface.modelgeneratedvertex = true;
7013         }
7014         else
7015         {
7016                 if (rsurface.entityskeletaltransform3x4)
7017                 {
7018                         r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7019                         r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7020                         r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7021                         r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7022                 }
7023                 else
7024                 {
7025                         r_refdef.stats[r_stat_batch_entitystatic_count]++;
7026                         r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7027                         r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7028                         r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7029                 }
7030                 rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
7031                 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.data_vertex3f_vertexbuffer;
7032                 rsurface.modelvertex3f_bufferoffset = model->surfmesh.data_vertex3f_bufferoffset;
7033                 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7034                 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.data_svector3f_vertexbuffer;
7035                 rsurface.modelsvector3f_bufferoffset = model->surfmesh.data_svector3f_bufferoffset;
7036                 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7037                 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.data_tvector3f_vertexbuffer;
7038                 rsurface.modeltvector3f_bufferoffset = model->surfmesh.data_tvector3f_bufferoffset;
7039                 rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
7040                 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.data_normal3f_vertexbuffer;
7041                 rsurface.modelnormal3f_bufferoffset = model->surfmesh.data_normal3f_bufferoffset;
7042                 rsurface.modelgeneratedvertex = false;
7043         }
7044         rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
7045         rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.data_lightmapcolor4f_vertexbuffer;
7046         rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.data_lightmapcolor4f_bufferoffset;
7047         rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
7048         rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.data_texcoordtexture2f_vertexbuffer;
7049         rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.data_texcoordtexture2f_bufferoffset;
7050         rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
7051         rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.data_texcoordlightmap2f_vertexbuffer;
7052         rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.data_texcoordlightmap2f_bufferoffset;
7053         rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7054         rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.data_skeletalindex4ub_vertexbuffer;
7055         rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.data_skeletalindex4ub_bufferoffset;
7056         rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7057         rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.data_skeletalweight4ub_vertexbuffer;
7058         rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.data_skeletalweight4ub_bufferoffset;
7059         rsurface.modelelement3i = model->surfmesh.data_element3i;
7060         rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7061         rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7062         rsurface.modelelement3s = model->surfmesh.data_element3s;
7063         rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7064         rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7065         rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7066         rsurface.modelnumvertices = model->surfmesh.num_vertices;
7067         rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7068         rsurface.modelsurfaces = model->data_surfaces;
7069         rsurface.batchgeneratedvertex = false;
7070         rsurface.batchfirstvertex = 0;
7071         rsurface.batchnumvertices = 0;
7072         rsurface.batchfirsttriangle = 0;
7073         rsurface.batchnumtriangles = 0;
7074         rsurface.batchvertex3f  = NULL;
7075         rsurface.batchvertex3f_vertexbuffer = NULL;
7076         rsurface.batchvertex3f_bufferoffset = 0;
7077         rsurface.batchsvector3f = NULL;
7078         rsurface.batchsvector3f_vertexbuffer = NULL;
7079         rsurface.batchsvector3f_bufferoffset = 0;
7080         rsurface.batchtvector3f = NULL;
7081         rsurface.batchtvector3f_vertexbuffer = NULL;
7082         rsurface.batchtvector3f_bufferoffset = 0;
7083         rsurface.batchnormal3f  = NULL;
7084         rsurface.batchnormal3f_vertexbuffer = NULL;
7085         rsurface.batchnormal3f_bufferoffset = 0;
7086         rsurface.batchlightmapcolor4f = NULL;
7087         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7088         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7089         rsurface.batchtexcoordtexture2f = NULL;
7090         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7091         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7092         rsurface.batchtexcoordlightmap2f = NULL;
7093         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7094         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7095         rsurface.batchskeletalindex4ub = NULL;
7096         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7097         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7098         rsurface.batchskeletalweight4ub = NULL;
7099         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7100         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7101         rsurface.batchelement3i = NULL;
7102         rsurface.batchelement3i_indexbuffer = NULL;
7103         rsurface.batchelement3i_bufferoffset = 0;
7104         rsurface.batchelement3s = NULL;
7105         rsurface.batchelement3s_indexbuffer = NULL;
7106         rsurface.batchelement3s_bufferoffset = 0;
7107         rsurface.forcecurrenttextureupdate = false;
7108 }
7109
7110 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)
7111 {
7112         rsurface.entity = r_refdef.scene.worldentity;
7113         if (r != 1.0f || g != 1.0f || b != 1.0f || a != 1.0f) {
7114                 // HACK to provide a valid entity with modded colors to R_GetCurrentTexture.
7115                 // A better approach could be making this copy only once per frame.
7116                 static entity_render_t custom_entity;
7117                 int q;
7118                 custom_entity = *rsurface.entity;
7119                 for (q = 0; q < 3; ++q) {
7120                         float colormod = q == 0 ? r : q == 1 ? g : b;
7121                         custom_entity.render_fullbright[q] *= colormod;
7122                         custom_entity.render_modellight_ambient[q] *= colormod;
7123                         custom_entity.render_modellight_diffuse[q] *= colormod;
7124                         custom_entity.render_lightmap_ambient[q] *= colormod;
7125                         custom_entity.render_lightmap_diffuse[q] *= colormod;
7126                         custom_entity.render_rtlight_diffuse[q] *= colormod;
7127                 }
7128                 custom_entity.alpha *= a;
7129                 rsurface.entity = &custom_entity;
7130         }
7131         rsurface.skeleton = NULL;
7132         rsurface.ent_skinnum = 0;
7133         rsurface.ent_qwskin = -1;
7134         rsurface.ent_flags = entflags;
7135         rsurface.shadertime = r_refdef.scene.time - shadertime;
7136         rsurface.modelnumvertices = numvertices;
7137         rsurface.modelnumtriangles = numtriangles;
7138         rsurface.matrix = *matrix;
7139         rsurface.inversematrix = *inversematrix;
7140         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7141         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7142         R_EntityMatrix(&rsurface.matrix);
7143         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7144         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7145         rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7146         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7147         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7148         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7149         memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7150         rsurface.frameblend[0].lerp = 1;
7151         rsurface.ent_alttextures = false;
7152         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7153         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7154         rsurface.entityskeletaltransform3x4 = NULL;
7155         rsurface.entityskeletaltransform3x4buffer = NULL;
7156         rsurface.entityskeletaltransform3x4offset = 0;
7157         rsurface.entityskeletaltransform3x4size = 0;
7158         rsurface.entityskeletalnumtransforms = 0;
7159         r_refdef.stats[r_stat_batch_entitycustom_count]++;
7160         r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7161         r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7162         r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7163         if (wanttangents)
7164         {
7165                 rsurface.modelvertex3f = (float *)vertex3f;
7166                 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7167                 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7168                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7169         }
7170         else if (wantnormals)
7171         {
7172                 rsurface.modelvertex3f = (float *)vertex3f;
7173                 rsurface.modelsvector3f = NULL;
7174                 rsurface.modeltvector3f = NULL;
7175                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7176         }
7177         else
7178         {
7179                 rsurface.modelvertex3f = (float *)vertex3f;
7180                 rsurface.modelsvector3f = NULL;
7181                 rsurface.modeltvector3f = NULL;
7182                 rsurface.modelnormal3f = NULL;
7183         }
7184         rsurface.modelvertex3f_vertexbuffer = 0;
7185         rsurface.modelvertex3f_bufferoffset = 0;
7186         rsurface.modelsvector3f_vertexbuffer = 0;
7187         rsurface.modelsvector3f_bufferoffset = 0;
7188         rsurface.modeltvector3f_vertexbuffer = 0;
7189         rsurface.modeltvector3f_bufferoffset = 0;
7190         rsurface.modelnormal3f_vertexbuffer = 0;
7191         rsurface.modelnormal3f_bufferoffset = 0;
7192         rsurface.modelgeneratedvertex = true;
7193         rsurface.modellightmapcolor4f  = (float *)color4f;
7194         rsurface.modellightmapcolor4f_vertexbuffer = 0;
7195         rsurface.modellightmapcolor4f_bufferoffset = 0;
7196         rsurface.modeltexcoordtexture2f  = (float *)texcoord2f;
7197         rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7198         rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7199         rsurface.modeltexcoordlightmap2f  = NULL;
7200         rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7201         rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7202         rsurface.modelskeletalindex4ub = NULL;
7203         rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7204         rsurface.modelskeletalindex4ub_bufferoffset = 0;
7205         rsurface.modelskeletalweight4ub = NULL;
7206         rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7207         rsurface.modelskeletalweight4ub_bufferoffset = 0;
7208         rsurface.modelelement3i = (int *)element3i;
7209         rsurface.modelelement3i_indexbuffer = NULL;
7210         rsurface.modelelement3i_bufferoffset = 0;
7211         rsurface.modelelement3s = (unsigned short *)element3s;
7212         rsurface.modelelement3s_indexbuffer = NULL;
7213         rsurface.modelelement3s_bufferoffset = 0;
7214         rsurface.modellightmapoffsets = NULL;
7215         rsurface.modelsurfaces = NULL;
7216         rsurface.batchgeneratedvertex = false;
7217         rsurface.batchfirstvertex = 0;
7218         rsurface.batchnumvertices = 0;
7219         rsurface.batchfirsttriangle = 0;
7220         rsurface.batchnumtriangles = 0;
7221         rsurface.batchvertex3f  = NULL;
7222         rsurface.batchvertex3f_vertexbuffer = NULL;
7223         rsurface.batchvertex3f_bufferoffset = 0;
7224         rsurface.batchsvector3f = NULL;
7225         rsurface.batchsvector3f_vertexbuffer = NULL;
7226         rsurface.batchsvector3f_bufferoffset = 0;
7227         rsurface.batchtvector3f = NULL;
7228         rsurface.batchtvector3f_vertexbuffer = NULL;
7229         rsurface.batchtvector3f_bufferoffset = 0;
7230         rsurface.batchnormal3f  = NULL;
7231         rsurface.batchnormal3f_vertexbuffer = NULL;
7232         rsurface.batchnormal3f_bufferoffset = 0;
7233         rsurface.batchlightmapcolor4f = NULL;
7234         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7235         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7236         rsurface.batchtexcoordtexture2f = NULL;
7237         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7238         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7239         rsurface.batchtexcoordlightmap2f = NULL;
7240         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7241         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7242         rsurface.batchskeletalindex4ub = NULL;
7243         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7244         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7245         rsurface.batchskeletalweight4ub = NULL;
7246         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7247         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7248         rsurface.batchelement3i = NULL;
7249         rsurface.batchelement3i_indexbuffer = NULL;
7250         rsurface.batchelement3i_bufferoffset = 0;
7251         rsurface.batchelement3s = NULL;
7252         rsurface.batchelement3s_indexbuffer = NULL;
7253         rsurface.batchelement3s_bufferoffset = 0;
7254         rsurface.forcecurrenttextureupdate = true;
7255
7256         if (rsurface.modelnumvertices && rsurface.modelelement3i)
7257         {
7258                 if ((wantnormals || wanttangents) && !normal3f)
7259                 {
7260                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7261                         Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7262                 }
7263                 if (wanttangents && !svector3f)
7264                 {
7265                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7266                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7267                         Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7268                 }
7269         }
7270 }
7271
7272 float RSurf_FogPoint(const float *v)
7273 {
7274         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7275         float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7276         float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7277         float FogHeightFade = r_refdef.fogheightfade;
7278         float fogfrac;
7279         unsigned int fogmasktableindex;
7280         if (r_refdef.fogplaneviewabove)
7281                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7282         else
7283                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7284         fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7285         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7286 }
7287
7288 float RSurf_FogVertex(const float *v)
7289 {
7290         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7291         float FogPlaneViewDist = rsurface.fogplaneviewdist;
7292         float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7293         float FogHeightFade = rsurface.fogheightfade;
7294         float fogfrac;
7295         unsigned int fogmasktableindex;
7296         if (r_refdef.fogplaneviewabove)
7297                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7298         else
7299                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7300         fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7301         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7302 }
7303
7304 void RSurf_UploadBuffersForBatch(void)
7305 {
7306         // 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)
7307         // note that if rsurface.batchvertex3f_vertexbuffer is NULL, dynamicvertex is forced as we don't account for the proper base vertex here.
7308         if (rsurface.batchvertex3f && !rsurface.batchvertex3f_vertexbuffer)
7309                 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
7310         if (rsurface.batchsvector3f && !rsurface.batchsvector3f_vertexbuffer)
7311                 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
7312         if (rsurface.batchtvector3f && !rsurface.batchtvector3f_vertexbuffer)
7313                 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
7314         if (rsurface.batchnormal3f && !rsurface.batchnormal3f_vertexbuffer)
7315                 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
7316         if (rsurface.batchlightmapcolor4f && !rsurface.batchlightmapcolor4f_vertexbuffer)
7317                 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
7318         if (rsurface.batchtexcoordtexture2f && !rsurface.batchtexcoordtexture2f_vertexbuffer)
7319                 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
7320         if (rsurface.batchtexcoordlightmap2f && !rsurface.batchtexcoordlightmap2f_vertexbuffer)
7321                 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
7322         if (rsurface.batchskeletalindex4ub && !rsurface.batchskeletalindex4ub_vertexbuffer)
7323                 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
7324         if (rsurface.batchskeletalweight4ub && !rsurface.batchskeletalweight4ub_vertexbuffer)
7325                 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
7326
7327         if (rsurface.batchelement3s && !rsurface.batchelement3s_indexbuffer)
7328                 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
7329         else if (rsurface.batchelement3i && !rsurface.batchelement3i_indexbuffer)
7330                 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
7331
7332         R_Mesh_VertexPointer(     3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
7333         R_Mesh_ColorPointer(      4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
7334         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
7335         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
7336         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
7337         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
7338         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
7339         R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
7340         R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
7341         R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
7342 }
7343
7344 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7345 {
7346         int i;
7347         for (i = 0;i < numelements;i++)
7348                 outelement3i[i] = inelement3i[i] + adjust;
7349 }
7350
7351 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7352 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7353 {
7354         int deformindex;
7355         int firsttriangle;
7356         int numtriangles;
7357         int firstvertex;
7358         int endvertex;
7359         int numvertices;
7360         int surfacefirsttriangle;
7361         int surfacenumtriangles;
7362         int surfacefirstvertex;
7363         int surfaceendvertex;
7364         int surfacenumvertices;
7365         int batchnumsurfaces = texturenumsurfaces;
7366         int batchnumvertices;
7367         int batchnumtriangles;
7368         int i, j;
7369         qboolean gaps;
7370         qboolean dynamicvertex;
7371         float amplitude;
7372         float animpos;
7373         float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7374         float waveparms[4];
7375         unsigned char *ub;
7376         q3shaderinfo_deform_t *deform;
7377         const msurface_t *surface, *firstsurface;
7378         if (!texturenumsurfaces)
7379                 return;
7380         // find vertex range of this surface batch
7381         gaps = false;
7382         firstsurface = texturesurfacelist[0];
7383         firsttriangle = firstsurface->num_firsttriangle;
7384         batchnumvertices = 0;
7385         batchnumtriangles = 0;
7386         firstvertex = endvertex = firstsurface->num_firstvertex;
7387         for (i = 0;i < texturenumsurfaces;i++)
7388         {
7389                 surface = texturesurfacelist[i];
7390                 if (surface != firstsurface + i)
7391                         gaps = true;
7392                 surfacefirstvertex = surface->num_firstvertex;
7393                 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7394                 surfacenumvertices = surface->num_vertices;
7395                 surfacenumtriangles = surface->num_triangles;
7396                 if (firstvertex > surfacefirstvertex)
7397                         firstvertex = surfacefirstvertex;
7398                 if (endvertex < surfaceendvertex)
7399                         endvertex = surfaceendvertex;
7400                 batchnumvertices += surfacenumvertices;
7401                 batchnumtriangles += surfacenumtriangles;
7402         }
7403
7404         r_refdef.stats[r_stat_batch_batches]++;
7405         if (gaps)
7406                 r_refdef.stats[r_stat_batch_withgaps]++;
7407         r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7408         r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7409         r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7410
7411         // we now know the vertex range used, and if there are any gaps in it
7412         rsurface.batchfirstvertex = firstvertex;
7413         rsurface.batchnumvertices = endvertex - firstvertex;
7414         rsurface.batchfirsttriangle = firsttriangle;
7415         rsurface.batchnumtriangles = batchnumtriangles;
7416
7417         // check if any dynamic vertex processing must occur
7418         dynamicvertex = false;
7419
7420         // we must use vertexbuffers for rendering, we can upload vertex buffers
7421         // easily enough but if the basevertex is non-zero it becomes more
7422         // difficult, so force dynamicvertex path in that case - it's suboptimal
7423         // but the most optimal case is to have the geometry sources provide their
7424         // own anyway.
7425         if (!rsurface.modelvertex3f_vertexbuffer && firstvertex != 0)
7426                 dynamicvertex = true;
7427
7428         // a cvar to force the dynamic vertex path to be taken, for debugging
7429         if (r_batch_debugdynamicvertexpath.integer)
7430         {
7431                 if (!dynamicvertex)
7432                 {
7433                         r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7434                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7435                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7436                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7437                 }
7438                 dynamicvertex = true;
7439         }
7440
7441         // if there is a chance of animated vertex colors, it's a dynamic batch
7442         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
7443         {
7444                 if (!dynamicvertex)
7445                 {
7446                         r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7447                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7448                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7449                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7450                 }
7451                 dynamicvertex = true;
7452         }
7453
7454         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7455         {
7456                 switch (deform->deform)
7457                 {
7458                 default:
7459                 case Q3DEFORM_PROJECTIONSHADOW:
7460                 case Q3DEFORM_TEXT0:
7461                 case Q3DEFORM_TEXT1:
7462                 case Q3DEFORM_TEXT2:
7463                 case Q3DEFORM_TEXT3:
7464                 case Q3DEFORM_TEXT4:
7465                 case Q3DEFORM_TEXT5:
7466                 case Q3DEFORM_TEXT6:
7467                 case Q3DEFORM_TEXT7:
7468                 case Q3DEFORM_NONE:
7469                         break;
7470                 case Q3DEFORM_AUTOSPRITE:
7471                         if (!dynamicvertex)
7472                         {
7473                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7474                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7475                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7476                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7477                         }
7478                         dynamicvertex = true;
7479                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7480                         break;
7481                 case Q3DEFORM_AUTOSPRITE2:
7482                         if (!dynamicvertex)
7483                         {
7484                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7485                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7486                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7487                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7488                         }
7489                         dynamicvertex = true;
7490                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7491                         break;
7492                 case Q3DEFORM_NORMAL:
7493                         if (!dynamicvertex)
7494                         {
7495                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7496                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7497                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7498                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7499                         }
7500                         dynamicvertex = true;
7501                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7502                         break;
7503                 case Q3DEFORM_WAVE:
7504                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7505                                 break; // if wavefunc is a nop, ignore this transform
7506                         if (!dynamicvertex)
7507                         {
7508                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7509                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7510                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7511                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7512                         }
7513                         dynamicvertex = true;
7514                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7515                         break;
7516                 case Q3DEFORM_BULGE:
7517                         if (!dynamicvertex)
7518                         {
7519                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7520                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7521                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7522                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7523                         }
7524                         dynamicvertex = true;
7525                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7526                         break;
7527                 case Q3DEFORM_MOVE:
7528                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7529                                 break; // if wavefunc is a nop, ignore this transform
7530                         if (!dynamicvertex)
7531                         {
7532                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7533                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7534                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7535                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7536                         }
7537                         dynamicvertex = true;
7538                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7539                         break;
7540                 }
7541         }
7542         if (rsurface.texture->materialshaderpass)
7543         {
7544                 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7545                 {
7546                 default:
7547                 case Q3TCGEN_TEXTURE:
7548                         break;
7549                 case Q3TCGEN_LIGHTMAP:
7550                         if (!dynamicvertex)
7551                         {
7552                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7553                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7554                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7555                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7556                         }
7557                         dynamicvertex = true;
7558                         batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7559                         break;
7560                 case Q3TCGEN_VECTOR:
7561                         if (!dynamicvertex)
7562                         {
7563                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7564                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7565                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7566                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7567                         }
7568                         dynamicvertex = true;
7569                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7570                         break;
7571                 case Q3TCGEN_ENVIRONMENT:
7572                         if (!dynamicvertex)
7573                         {
7574                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7575                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7576                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7577                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7578                         }
7579                         dynamicvertex = true;
7580                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7581                         break;
7582                 }
7583                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7584                 {
7585                         if (!dynamicvertex)
7586                         {
7587                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7588                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7589                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7590                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7591                         }
7592                         dynamicvertex = true;
7593                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7594                 }
7595         }
7596
7597         // the caller can specify BATCHNEED_NOGAPS to force a batch with
7598         // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7599         // we ensure this by treating the vertex batch as dynamic...
7600         if ((batchneed & BATCHNEED_ALWAYSCOPY) || ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0)))
7601         {
7602                 if (!dynamicvertex)
7603                 {
7604                         r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7605                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7606                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7607                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7608                 }
7609                 dynamicvertex = true;
7610         }
7611
7612         // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7613         if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7614                 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7615
7616         rsurface.batchvertex3f = rsurface.modelvertex3f;
7617         rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7618         rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7619         rsurface.batchsvector3f = rsurface.modelsvector3f;
7620         rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7621         rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7622         rsurface.batchtvector3f = rsurface.modeltvector3f;
7623         rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7624         rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7625         rsurface.batchnormal3f = rsurface.modelnormal3f;
7626         rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7627         rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7628         rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7629         rsurface.batchlightmapcolor4f_vertexbuffer  = rsurface.modellightmapcolor4f_vertexbuffer;
7630         rsurface.batchlightmapcolor4f_bufferoffset  = rsurface.modellightmapcolor4f_bufferoffset;
7631         rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7632         rsurface.batchtexcoordtexture2f_vertexbuffer  = rsurface.modeltexcoordtexture2f_vertexbuffer;
7633         rsurface.batchtexcoordtexture2f_bufferoffset  = rsurface.modeltexcoordtexture2f_bufferoffset;
7634         rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7635         rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7636         rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7637         rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7638         rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7639         rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7640         rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7641         rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7642         rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7643         rsurface.batchelement3i = rsurface.modelelement3i;
7644         rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7645         rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7646         rsurface.batchelement3s = rsurface.modelelement3s;
7647         rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7648         rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7649         rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7650         rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7651         rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7652         rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7653         rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7654
7655         // if any dynamic vertex processing has to occur in software, we copy the
7656         // entire surface list together before processing to rebase the vertices
7657         // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7658         //
7659         // if any gaps exist and we do not have a static vertex buffer, we have to
7660         // copy the surface list together to avoid wasting upload bandwidth on the
7661         // vertices in the gaps.
7662         //
7663         // if gaps exist and we have a static vertex buffer, we can choose whether
7664         // to combine the index buffer ranges into one dynamic index buffer or
7665         // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7666         //
7667         // in many cases the batch is reduced to one draw call.
7668
7669         rsurface.batchmultidraw = false;
7670         rsurface.batchmultidrawnumsurfaces = 0;
7671         rsurface.batchmultidrawsurfacelist = NULL;
7672
7673         if (!dynamicvertex)
7674         {
7675                 // static vertex data, just set pointers...
7676                 rsurface.batchgeneratedvertex = false;
7677                 // if there are gaps, we want to build a combined index buffer,
7678                 // otherwise use the original static buffer with an appropriate offset
7679                 if (gaps)
7680                 {
7681                         r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7682                         r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7683                         r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7684                         r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7685                         if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7686                         {
7687                                 rsurface.batchmultidraw = true;
7688                                 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7689                                 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7690                                 return;
7691                         }
7692                         // build a new triangle elements array for this batch
7693                         rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7694                         rsurface.batchfirsttriangle = 0;
7695                         numtriangles = 0;
7696                         for (i = 0;i < texturenumsurfaces;i++)
7697                         {
7698                                 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7699                                 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7700                                 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7701                                 numtriangles += surfacenumtriangles;
7702                         }
7703                         rsurface.batchelement3i_indexbuffer = NULL;
7704                         rsurface.batchelement3i_bufferoffset = 0;
7705                         rsurface.batchelement3s = NULL;
7706                         rsurface.batchelement3s_indexbuffer = NULL;
7707                         rsurface.batchelement3s_bufferoffset = 0;
7708                         if (endvertex <= 65536)
7709                         {
7710                                 // make a 16bit (unsigned short) index array if possible
7711                                 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7712                                 for (i = 0;i < numtriangles*3;i++)
7713                                         rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7714                         }
7715                 }
7716                 else
7717                 {
7718                         r_refdef.stats[r_stat_batch_fast_batches] += 1;
7719                         r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
7720                         r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
7721                         r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
7722                 }
7723                 return;
7724         }
7725
7726         // something needs software processing, do it for real...
7727         // we only directly handle separate array data in this case and then
7728         // generate interleaved data if needed...
7729         rsurface.batchgeneratedvertex = true;
7730         r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
7731         r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
7732         r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
7733         r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
7734
7735         // now copy the vertex data into a combined array and make an index array
7736         // (this is what Quake3 does all the time)
7737         // we also apply any skeletal animation here that would have been done in
7738         // the vertex shader, because most of the dynamic vertex animation cases
7739         // need actual vertex positions and normals
7740         //if (dynamicvertex)
7741         {
7742                 rsurface.batchvertex3f = NULL;
7743                 rsurface.batchvertex3f_vertexbuffer = NULL;
7744                 rsurface.batchvertex3f_bufferoffset = 0;
7745                 rsurface.batchsvector3f = NULL;
7746                 rsurface.batchsvector3f_vertexbuffer = NULL;
7747                 rsurface.batchsvector3f_bufferoffset = 0;
7748                 rsurface.batchtvector3f = NULL;
7749                 rsurface.batchtvector3f_vertexbuffer = NULL;
7750                 rsurface.batchtvector3f_bufferoffset = 0;
7751                 rsurface.batchnormal3f = NULL;
7752                 rsurface.batchnormal3f_vertexbuffer = NULL;
7753                 rsurface.batchnormal3f_bufferoffset = 0;
7754                 rsurface.batchlightmapcolor4f = NULL;
7755                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7756                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7757                 rsurface.batchtexcoordtexture2f = NULL;
7758                 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7759                 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7760                 rsurface.batchtexcoordlightmap2f = NULL;
7761                 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7762                 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7763                 rsurface.batchskeletalindex4ub = NULL;
7764                 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7765                 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7766                 rsurface.batchskeletalweight4ub = NULL;
7767                 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7768                 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7769                 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7770                 rsurface.batchelement3i_indexbuffer = NULL;
7771                 rsurface.batchelement3i_bufferoffset = 0;
7772                 rsurface.batchelement3s = NULL;
7773                 rsurface.batchelement3s_indexbuffer = NULL;
7774                 rsurface.batchelement3s_bufferoffset = 0;
7775                 rsurface.batchskeletaltransform3x4buffer = NULL;
7776                 rsurface.batchskeletaltransform3x4offset = 0;
7777                 rsurface.batchskeletaltransform3x4size = 0;
7778                 // we'll only be setting up certain arrays as needed
7779                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7780                         rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7781                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7782                         rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7783                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7784                 {
7785                         rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7786                         rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7787                 }
7788                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7789                         rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
7790                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7791                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7792                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7793                         rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7794                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7795                 {
7796                         rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7797                         rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7798                 }
7799                 numvertices = 0;
7800                 numtriangles = 0;
7801                 for (i = 0;i < texturenumsurfaces;i++)
7802                 {
7803                         surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
7804                         surfacenumvertices = texturesurfacelist[i]->num_vertices;
7805                         surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7806                         surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7807                         // copy only the data requested
7808                         if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
7809                         {
7810                                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7811                                 {
7812                                         if (rsurface.batchvertex3f)
7813                                                 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7814                                         else
7815                                                 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7816                                 }
7817                                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7818                                 {
7819                                         if (rsurface.modelnormal3f)
7820                                                 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7821                                         else
7822                                                 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7823                                 }
7824                                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7825                                 {
7826                                         if (rsurface.modelsvector3f)
7827                                         {
7828                                                 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7829                                                 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7830                                         }
7831                                         else
7832                                         {
7833                                                 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7834                                                 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7835                                         }
7836                                 }
7837                                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7838                                 {
7839                                         if (rsurface.modellightmapcolor4f)
7840                                                 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
7841                                         else
7842                                                 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
7843                                 }
7844                                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7845                                 {
7846                                         if (rsurface.modeltexcoordtexture2f)
7847                                                 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7848                                         else
7849                                                 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7850                                 }
7851                                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7852                                 {
7853                                         if (rsurface.modeltexcoordlightmap2f)
7854                                                 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7855                                         else
7856                                                 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7857                                 }
7858                                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7859                                 {
7860                                         if (rsurface.modelskeletalindex4ub)
7861                                         {
7862                                                 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7863                                                 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7864                                         }
7865                                         else
7866                                         {
7867                                                 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7868                                                 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7869                                                 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
7870                                                 for (j = 0;j < surfacenumvertices;j++)
7871                                                         ub[j*4] = 255;
7872                                         }
7873                                 }
7874                         }
7875                         RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
7876                         numvertices += surfacenumvertices;
7877                         numtriangles += surfacenumtriangles;
7878                 }
7879
7880                 // generate a 16bit index array as well if possible
7881                 // (in general, dynamic batches fit)
7882                 if (numvertices <= 65536)
7883                 {
7884                         rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7885                         for (i = 0;i < numtriangles*3;i++)
7886                                 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7887                 }
7888
7889                 // since we've copied everything, the batch now starts at 0
7890                 rsurface.batchfirstvertex = 0;
7891                 rsurface.batchnumvertices = batchnumvertices;
7892                 rsurface.batchfirsttriangle = 0;
7893                 rsurface.batchnumtriangles = batchnumtriangles;
7894         }
7895
7896         // apply skeletal animation that would have been done in the vertex shader
7897         if (rsurface.batchskeletaltransform3x4)
7898         {
7899                 const unsigned char *si;
7900                 const unsigned char *sw;
7901                 const float *t[4];
7902                 const float *b = rsurface.batchskeletaltransform3x4;
7903                 float *vp, *vs, *vt, *vn;
7904                 float w[4];
7905                 float m[3][4], n[3][4];
7906                 float tp[3], ts[3], tt[3], tn[3];
7907                 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
7908                 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
7909                 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
7910                 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
7911                 si = rsurface.batchskeletalindex4ub;
7912                 sw = rsurface.batchskeletalweight4ub;
7913                 vp = rsurface.batchvertex3f;
7914                 vs = rsurface.batchsvector3f;
7915                 vt = rsurface.batchtvector3f;
7916                 vn = rsurface.batchnormal3f;
7917                 memset(m[0], 0, sizeof(m));
7918                 memset(n[0], 0, sizeof(n));
7919                 for (i = 0;i < batchnumvertices;i++)
7920                 {
7921                         t[0] = b + si[0]*12;
7922                         if (sw[0] == 255)
7923                         {
7924                                 // common case - only one matrix
7925                                 m[0][0] = t[0][ 0];
7926                                 m[0][1] = t[0][ 1];
7927                                 m[0][2] = t[0][ 2];
7928                                 m[0][3] = t[0][ 3];
7929                                 m[1][0] = t[0][ 4];
7930                                 m[1][1] = t[0][ 5];
7931                                 m[1][2] = t[0][ 6];
7932                                 m[1][3] = t[0][ 7];
7933                                 m[2][0] = t[0][ 8];
7934                                 m[2][1] = t[0][ 9];
7935                                 m[2][2] = t[0][10];
7936                                 m[2][3] = t[0][11];
7937                         }
7938                         else if (sw[2] + sw[3])
7939                         {
7940                                 // blend 4 matrices
7941                                 t[1] = b + si[1]*12;
7942                                 t[2] = b + si[2]*12;
7943                                 t[3] = b + si[3]*12;
7944                                 w[0] = sw[0] * (1.0f / 255.0f);
7945                                 w[1] = sw[1] * (1.0f / 255.0f);
7946                                 w[2] = sw[2] * (1.0f / 255.0f);
7947                                 w[3] = sw[3] * (1.0f / 255.0f);
7948                                 // blend the matrices
7949                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
7950                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
7951                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
7952                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
7953                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
7954                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
7955                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
7956                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
7957                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
7958                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
7959                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
7960                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
7961                         }
7962                         else
7963                         {
7964                                 // blend 2 matrices
7965                                 t[1] = b + si[1]*12;
7966                                 w[0] = sw[0] * (1.0f / 255.0f);
7967                                 w[1] = sw[1] * (1.0f / 255.0f);
7968                                 // blend the matrices
7969                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
7970                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
7971                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
7972                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
7973                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
7974                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
7975                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
7976                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
7977                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
7978                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
7979                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
7980                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
7981                         }
7982                         si += 4;
7983                         sw += 4;
7984                         // modify the vertex
7985                         VectorCopy(vp, tp);
7986                         vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
7987                         vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
7988                         vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
7989                         vp += 3;
7990                         if (vn)
7991                         {
7992                                 // the normal transformation matrix is a set of cross products...
7993                                 CrossProduct(m[1], m[2], n[0]);
7994                                 CrossProduct(m[2], m[0], n[1]);
7995                                 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
7996                                 VectorCopy(vn, tn);
7997                                 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
7998                                 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
7999                                 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8000                                 VectorNormalize(vn);
8001                                 vn += 3;
8002                                 if (vs)
8003                                 {
8004                                         VectorCopy(vs, ts);
8005                                         vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8006                                         vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8007                                         vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8008                                         VectorNormalize(vs);
8009                                         vs += 3;
8010                                         VectorCopy(vt, tt);
8011                                         vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8012                                         vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8013                                         vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8014                                         VectorNormalize(vt);
8015                                         vt += 3;
8016                                 }
8017                         }
8018                 }
8019                 rsurface.batchskeletaltransform3x4 = NULL;
8020                 rsurface.batchskeletalnumtransforms = 0;
8021         }
8022
8023         // q1bsp surfaces rendered in vertex color mode have to have colors
8024         // calculated based on lightstyles
8025         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
8026         {
8027                 // generate color arrays for the surfaces in this list
8028                 int c[4];
8029                 int scale;
8030                 int size3;
8031                 const int *offsets;
8032                 const unsigned char *lm;
8033                 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8034                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8035                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8036                 numvertices = 0;
8037                 for (i = 0;i < texturenumsurfaces;i++)
8038                 {
8039                         surface = texturesurfacelist[i];
8040                         offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8041                         surfacenumvertices = surface->num_vertices;
8042                         if (surface->lightmapinfo->samples)
8043                         {
8044                                 for (j = 0;j < surfacenumvertices;j++)
8045                                 {
8046                                         lm = surface->lightmapinfo->samples + offsets[j];
8047                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8048                                         VectorScale(lm, scale, c);
8049                                         if (surface->lightmapinfo->styles[1] != 255)
8050                                         {
8051                                                 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8052                                                 lm += size3;
8053                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8054                                                 VectorMA(c, scale, lm, c);
8055                                                 if (surface->lightmapinfo->styles[2] != 255)
8056                                                 {
8057                                                         lm += size3;
8058                                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8059                                                         VectorMA(c, scale, lm, c);
8060                                                         if (surface->lightmapinfo->styles[3] != 255)
8061                                                         {
8062                                                                 lm += size3;
8063                                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8064                                                                 VectorMA(c, scale, lm, c);
8065                                                         }
8066                                                 }
8067                                         }
8068                                         c[0] >>= 7;
8069                                         c[1] >>= 7;
8070                                         c[2] >>= 7;
8071                                         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);
8072                                         numvertices++;
8073                                 }
8074                         }
8075                         else
8076                         {
8077                                 for (j = 0;j < surfacenumvertices;j++)
8078                                 {
8079                                         Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8080                                         numvertices++;
8081                                 }
8082                         }
8083                 }
8084         }
8085
8086         // if vertices are deformed (sprite flares and things in maps, possibly
8087         // water waves, bulges and other deformations), modify the copied vertices
8088         // in place
8089         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8090         {
8091                 float scale;
8092                 switch (deform->deform)
8093                 {
8094                 default:
8095                 case Q3DEFORM_PROJECTIONSHADOW:
8096                 case Q3DEFORM_TEXT0:
8097                 case Q3DEFORM_TEXT1:
8098                 case Q3DEFORM_TEXT2:
8099                 case Q3DEFORM_TEXT3:
8100                 case Q3DEFORM_TEXT4:
8101                 case Q3DEFORM_TEXT5:
8102                 case Q3DEFORM_TEXT6:
8103                 case Q3DEFORM_TEXT7:
8104                 case Q3DEFORM_NONE:
8105                         break;
8106                 case Q3DEFORM_AUTOSPRITE:
8107                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8108                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8109                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8110                         VectorNormalize(newforward);
8111                         VectorNormalize(newright);
8112                         VectorNormalize(newup);
8113 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8114 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8115 //                      rsurface.batchvertex3f_bufferoffset = 0;
8116 //                      rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8117 //                      rsurface.batchsvector3f_vertexbuffer = NULL;
8118 //                      rsurface.batchsvector3f_bufferoffset = 0;
8119 //                      rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8120 //                      rsurface.batchtvector3f_vertexbuffer = NULL;
8121 //                      rsurface.batchtvector3f_bufferoffset = 0;
8122 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8123 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8124 //                      rsurface.batchnormal3f_bufferoffset = 0;
8125                         // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8126                         if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8127                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8128                         if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8129                                 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);
8130                         // a single autosprite surface can contain multiple sprites...
8131                         for (j = 0;j < batchnumvertices - 3;j += 4)
8132                         {
8133                                 VectorClear(center);
8134                                 for (i = 0;i < 4;i++)
8135                                         VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8136                                 VectorScale(center, 0.25f, center);
8137                                 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8138                                 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8139                                 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8140                                 for (i = 0;i < 4;i++)
8141                                 {
8142                                         VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8143                                         VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8144                                 }
8145                         }
8146                         // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8147                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8148                         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);
8149                         break;
8150                 case Q3DEFORM_AUTOSPRITE2:
8151                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8152                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8153                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8154                         VectorNormalize(newforward);
8155                         VectorNormalize(newright);
8156                         VectorNormalize(newup);
8157 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8158 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8159 //                      rsurface.batchvertex3f_bufferoffset = 0;
8160                         {
8161                                 const float *v1, *v2;
8162                                 vec3_t start, end;
8163                                 float f, l;
8164                                 struct
8165                                 {
8166                                         float length2;
8167                                         const float *v1;
8168                                         const float *v2;
8169                                 }
8170                                 shortest[2];
8171                                 memset(shortest, 0, sizeof(shortest));
8172                                 // a single autosprite surface can contain multiple sprites...
8173                                 for (j = 0;j < batchnumvertices - 3;j += 4)
8174                                 {
8175                                         VectorClear(center);
8176                                         for (i = 0;i < 4;i++)
8177                                                 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8178                                         VectorScale(center, 0.25f, center);
8179                                         // find the two shortest edges, then use them to define the
8180                                         // axis vectors for rotating around the central axis
8181                                         for (i = 0;i < 6;i++)
8182                                         {
8183                                                 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8184                                                 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8185                                                 l = VectorDistance2(v1, v2);
8186                                                 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8187                                                 if (v1[2] != v2[2])
8188                                                         l += (1.0f / 1024.0f);
8189                                                 if (shortest[0].length2 > l || i == 0)
8190                                                 {
8191                                                         shortest[1] = shortest[0];
8192                                                         shortest[0].length2 = l;
8193                                                         shortest[0].v1 = v1;
8194                                                         shortest[0].v2 = v2;
8195                                                 }
8196                                                 else if (shortest[1].length2 > l || i == 1)
8197                                                 {
8198                                                         shortest[1].length2 = l;
8199                                                         shortest[1].v1 = v1;
8200                                                         shortest[1].v2 = v2;
8201                                                 }
8202                                         }
8203                                         VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8204                                         VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8205                                         // this calculates the right vector from the shortest edge
8206                                         // and the up vector from the edge midpoints
8207                                         VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8208                                         VectorNormalize(right);
8209                                         VectorSubtract(end, start, up);
8210                                         VectorNormalize(up);
8211                                         // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8212                                         VectorSubtract(rsurface.localvieworigin, center, forward);
8213                                         //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8214                                         VectorNegate(forward, forward);
8215                                         VectorReflect(forward, 0, up, forward);
8216                                         VectorNormalize(forward);
8217                                         CrossProduct(up, forward, newright);
8218                                         VectorNormalize(newright);
8219                                         // rotate the quad around the up axis vector, this is made
8220                                         // especially easy by the fact we know the quad is flat,
8221                                         // so we only have to subtract the center position and
8222                                         // measure distance along the right vector, and then
8223                                         // multiply that by the newright vector and add back the
8224                                         // center position
8225                                         // we also need to subtract the old position to undo the
8226                                         // displacement from the center, which we do with a
8227                                         // DotProduct, the subtraction/addition of center is also
8228                                         // optimized into DotProducts here
8229                                         l = DotProduct(right, center);
8230                                         for (i = 0;i < 4;i++)
8231                                         {
8232                                                 v1 = rsurface.batchvertex3f + 3*(j+i);
8233                                                 f = DotProduct(right, v1) - l;
8234                                                 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8235                                         }
8236                                 }
8237                         }
8238                         if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8239                         {
8240 //                              rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8241 //                              rsurface.batchnormal3f_vertexbuffer = NULL;
8242 //                              rsurface.batchnormal3f_bufferoffset = 0;
8243                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8244                         }
8245                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8246                         {
8247 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8248 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8249 //                              rsurface.batchsvector3f_bufferoffset = 0;
8250 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8251 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8252 //                              rsurface.batchtvector3f_bufferoffset = 0;
8253                                 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);
8254                         }
8255                         break;
8256                 case Q3DEFORM_NORMAL:
8257                         // deform the normals to make reflections wavey
8258                         rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8259                         rsurface.batchnormal3f_vertexbuffer = NULL;
8260                         rsurface.batchnormal3f_bufferoffset = 0;
8261                         for (j = 0;j < batchnumvertices;j++)
8262                         {
8263                                 float vertex[3];
8264                                 float *normal = rsurface.batchnormal3f + 3*j;
8265                                 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8266                                 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8267                                 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8268                                 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8269                                 VectorNormalize(normal);
8270                         }
8271                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8272                         {
8273 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8274 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8275 //                              rsurface.batchsvector3f_bufferoffset = 0;
8276 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8277 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8278 //                              rsurface.batchtvector3f_bufferoffset = 0;
8279                                 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);
8280                         }
8281                         break;
8282                 case Q3DEFORM_WAVE:
8283                         // deform vertex array to make wavey water and flags and such
8284                         waveparms[0] = deform->waveparms[0];
8285                         waveparms[1] = deform->waveparms[1];
8286                         waveparms[2] = deform->waveparms[2];
8287                         waveparms[3] = deform->waveparms[3];
8288                         if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8289                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8290                         // this is how a divisor of vertex influence on deformation
8291                         animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8292                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8293 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8294 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8295 //                      rsurface.batchvertex3f_bufferoffset = 0;
8296 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8297 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8298 //                      rsurface.batchnormal3f_bufferoffset = 0;
8299                         for (j = 0;j < batchnumvertices;j++)
8300                         {
8301                                 // if the wavefunc depends on time, evaluate it per-vertex
8302                                 if (waveparms[3])
8303                                 {
8304                                         waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8305                                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8306                                 }
8307                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8308                         }
8309                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8310                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8311                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8312                         {
8313 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8314 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8315 //                              rsurface.batchsvector3f_bufferoffset = 0;
8316 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8317 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8318 //                              rsurface.batchtvector3f_bufferoffset = 0;
8319                                 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);
8320                         }
8321                         break;
8322                 case Q3DEFORM_BULGE:
8323                         // deform vertex array to make the surface have moving bulges
8324 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8325 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8326 //                      rsurface.batchvertex3f_bufferoffset = 0;
8327 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8328 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8329 //                      rsurface.batchnormal3f_bufferoffset = 0;
8330                         for (j = 0;j < batchnumvertices;j++)
8331                         {
8332                                 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8333                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8334                         }
8335                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8336                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8337                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8338                         {
8339 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8340 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8341 //                              rsurface.batchsvector3f_bufferoffset = 0;
8342 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8343 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8344 //                              rsurface.batchtvector3f_bufferoffset = 0;
8345                                 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);
8346                         }
8347                         break;
8348                 case Q3DEFORM_MOVE:
8349                         // deform vertex array
8350                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8351                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8352                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8353                         VectorScale(deform->parms, scale, waveparms);
8354 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8355 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8356 //                      rsurface.batchvertex3f_bufferoffset = 0;
8357                         for (j = 0;j < batchnumvertices;j++)
8358                                 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8359                         break;
8360                 }
8361         }
8362
8363         if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8364         {
8365         // generate texcoords based on the chosen texcoord source
8366                 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8367                 {
8368                 default:
8369                 case Q3TCGEN_TEXTURE:
8370                         break;
8371                 case Q3TCGEN_LIGHTMAP:
8372         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8373         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8374         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8375                         if (rsurface.batchtexcoordlightmap2f)
8376                                 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8377                         break;
8378                 case Q3TCGEN_VECTOR:
8379         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8380         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8381         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8382                         for (j = 0;j < batchnumvertices;j++)
8383                         {
8384                                 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8385                                 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8386                         }
8387                         break;
8388                 case Q3TCGEN_ENVIRONMENT:
8389                         // make environment reflections using a spheremap
8390                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8391                         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8392                         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8393                         for (j = 0;j < batchnumvertices;j++)
8394                         {
8395                                 // identical to Q3A's method, but executed in worldspace so
8396                                 // carried models can be shiny too
8397
8398                                 float viewer[3], d, reflected[3], worldreflected[3];
8399
8400                                 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8401                                 // VectorNormalize(viewer);
8402
8403                                 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8404
8405                                 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8406                                 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8407                                 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8408                                 // note: this is proportinal to viewer, so we can normalize later
8409
8410                                 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8411                                 VectorNormalize(worldreflected);
8412
8413                                 // note: this sphere map only uses world x and z!
8414                                 // so positive and negative y will LOOK THE SAME.
8415                                 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8416                                 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8417                         }
8418                         break;
8419                 }
8420                 // the only tcmod that needs software vertex processing is turbulent, so
8421                 // check for it here and apply the changes if needed
8422                 // and we only support that as the first one
8423                 // (handling a mixture of turbulent and other tcmods would be problematic
8424                 //  without punting it entirely to a software path)
8425                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8426                 {
8427                         amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8428                         animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8429         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8430         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8431         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8432                         for (j = 0;j < batchnumvertices;j++)
8433                         {
8434                                 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);
8435                                 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8436                         }
8437                 }
8438         }
8439 }
8440
8441 void RSurf_DrawBatch(void)
8442 {
8443         // sometimes a zero triangle surface (usually a degenerate patch) makes it
8444         // through the pipeline, killing it earlier in the pipeline would have
8445         // per-surface overhead rather than per-batch overhead, so it's best to
8446         // reject it here, before it hits glDraw.
8447         if (rsurface.batchnumtriangles == 0)
8448                 return;
8449 #if 0
8450         // batch debugging code
8451         if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8452         {
8453                 int i;
8454                 int j;
8455                 int c;
8456                 const int *e;
8457                 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8458                 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8459                 {
8460                         c = e[i];
8461                         for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8462                         {
8463                                 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8464                                 {
8465                                         if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8466                                                 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);
8467                                         break;
8468                                 }
8469                         }
8470                 }
8471         }
8472 #endif
8473         if (rsurface.batchmultidraw)
8474         {
8475                 // issue multiple draws rather than copying index data
8476                 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8477                 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8478                 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8479                 for (i = 0;i < numsurfaces;)
8480                 {
8481                         // combine consecutive surfaces as one draw
8482                         for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8483                                 if (surfacelist[j] != surfacelist[k] + 1)
8484                                         break;
8485                         firstvertex = surfacelist[i]->num_firstvertex;
8486                         endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8487                         firsttriangle = surfacelist[i]->num_firsttriangle;
8488                         endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8489                         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);
8490                         i = j;
8491                 }
8492         }
8493         else
8494         {
8495                 // there is only one consecutive run of index data (may have been combined)
8496                 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);
8497         }
8498 }
8499
8500 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8501 {
8502         // pick the closest matching water plane
8503         int planeindex, vertexindex, bestplaneindex = -1;
8504         float d, bestd;
8505         vec3_t vert;
8506         const float *v;
8507         r_waterstate_waterplane_t *p;
8508         qboolean prepared = false;
8509         bestd = 0;
8510         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8511         {
8512                 if(p->camera_entity != rsurface.texture->camera_entity)
8513                         continue;
8514                 d = 0;
8515                 if(!prepared)
8516                 {
8517                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8518                         prepared = true;
8519                         if(rsurface.batchnumvertices == 0)
8520                                 break;
8521                 }
8522                 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8523                 {
8524                         Matrix4x4_Transform(&rsurface.matrix, v, vert);
8525                         d += fabs(PlaneDiff(vert, &p->plane));
8526                 }
8527                 if (bestd > d || bestplaneindex < 0)
8528                 {
8529                         bestd = d;
8530                         bestplaneindex = planeindex;
8531                 }
8532         }
8533         return bestplaneindex;
8534         // NOTE: this MAY return a totally unrelated water plane; we can ignore
8535         // this situation though, as it might be better to render single larger
8536         // batches with useless stuff (backface culled for example) than to
8537         // render multiple smaller batches
8538 }
8539
8540 void RSurf_SetupDepthAndCulling(void)
8541 {
8542         // submodels are biased to avoid z-fighting with world surfaces that they
8543         // may be exactly overlapping (avoids z-fighting artifacts on certain
8544         // doors and things in Quake maps)
8545         GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8546         GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8547         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8548         GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8549 }
8550
8551 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8552 {
8553         int i, j;
8554         // transparent sky would be ridiculous
8555         if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8556                 return;
8557         R_SetupShader_Generic_NoTexture(false, false);
8558         skyrenderlater = true;
8559         RSurf_SetupDepthAndCulling();
8560         GL_DepthMask(true);
8561
8562         // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8563         if (r_sky_scissor.integer)
8564         {
8565                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8566                 for (i = 0; i < texturenumsurfaces; i++)
8567                 {
8568                         const msurface_t *surf = texturesurfacelist[i];
8569                         const float *v;
8570                         float p[3];
8571                         float mins[3], maxs[3];
8572                         int scissor[4];
8573                         for (j = 0, v = rsurface.batchvertex3f + 3 * surf->num_firstvertex; j < surf->num_vertices; j++, v += 3)
8574                         {
8575                                 Matrix4x4_Transform(&rsurface.matrix, v, p);
8576                                 if (j > 0)
8577                                 {
8578                                         if (mins[0] > p[0]) mins[0] = p[0];
8579                                         if (mins[1] > p[1]) mins[1] = p[1];
8580                                         if (mins[2] > p[2]) mins[2] = p[2];
8581                                         if (maxs[0] < p[0]) maxs[0] = p[0];
8582                                         if (maxs[1] < p[1]) maxs[1] = p[1];
8583                                         if (maxs[2] < p[2]) maxs[2] = p[2];
8584                                 }
8585                                 else
8586                                 {
8587                                         VectorCopy(p, mins);
8588                                         VectorCopy(p, maxs);
8589                                 }
8590                         }
8591                         if (!R_ScissorForBBox(mins, maxs, scissor))
8592                         {
8593                                 if (skyscissor[2])
8594                                 {
8595                                         if (skyscissor[0] > scissor[0])
8596                                         {
8597                                                 skyscissor[2] += skyscissor[0] - scissor[0];
8598                                                 skyscissor[0] = scissor[0];
8599                                         }
8600                                         if (skyscissor[1] > scissor[1])
8601                                         {
8602                                                 skyscissor[3] += skyscissor[1] - scissor[1];
8603                                                 skyscissor[1] = scissor[1];
8604                                         }
8605                                         if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8606                                                 skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8607                                         if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8608                                                 skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8609                                 }
8610                                 else
8611                                         Vector4Copy(scissor, skyscissor);
8612                         }
8613                 }
8614         }
8615
8616         // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8617         // skymasking on them, and Quake3 never did sky masking (unlike
8618         // software Quake and software Quake2), so disable the sky masking
8619         // in Quake3 maps as it causes problems with q3map2 sky tricks,
8620         // and skymasking also looks very bad when noclipping outside the
8621         // level, so don't use it then either.
8622         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)
8623         {
8624                 R_Mesh_ResetTextureState();
8625                 if (skyrendermasked)
8626                 {
8627                         R_SetupShader_DepthOrShadow(false, false, false);
8628                         // depth-only (masking)
8629                         GL_ColorMask(0, 0, 0, 0);
8630                         // just to make sure that braindead drivers don't draw
8631                         // anything despite that colormask...
8632                         GL_BlendFunc(GL_ZERO, GL_ONE);
8633                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8634                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8635                 }
8636                 else
8637                 {
8638                         R_SetupShader_Generic_NoTexture(false, false);
8639                         // fog sky
8640                         GL_BlendFunc(GL_ONE, GL_ZERO);
8641                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8642                         GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
8643                         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
8644                 }
8645                 RSurf_DrawBatch();
8646                 if (skyrendermasked)
8647                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8648         }
8649         R_Mesh_ResetTextureState();
8650         GL_Color(1, 1, 1, 1);
8651 }
8652
8653 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
8654 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
8655 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass, qboolean ui)
8656 {
8657         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
8658                 return;
8659         if (prepass)
8660         {
8661                 // render screenspace normalmap to texture
8662                 GL_DepthMask(true);
8663                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false);
8664                 RSurf_DrawBatch();
8665                 return;
8666         }
8667
8668         // bind lightmap texture
8669
8670         // water/refraction/reflection/camera surfaces have to be handled specially
8671         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
8672         {
8673                 int start, end, startplaneindex;
8674                 for (start = 0;start < texturenumsurfaces;start = end)
8675                 {
8676                         startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
8677                         if(startplaneindex < 0)
8678                         {
8679                                 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
8680                                 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
8681                                 end = start + 1;
8682                                 continue;
8683                         }
8684                         for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
8685                                 ;
8686                         // now that we have a batch using the same planeindex, render it
8687                         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
8688                         {
8689                                 // render water or distortion background
8690                                 GL_DepthMask(true);
8691                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8692                                 RSurf_DrawBatch();
8693                                 // blend surface on top
8694                                 GL_DepthMask(false);
8695                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false);
8696                                 RSurf_DrawBatch();
8697                         }
8698                         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
8699                         {
8700                                 // render surface with reflection texture as input
8701                                 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8702                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8703                                 RSurf_DrawBatch();
8704                         }
8705                 }
8706                 return;
8707         }
8708
8709         // render surface batch normally
8710         GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8711         R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0 || ui);
8712         RSurf_DrawBatch();
8713 }
8714
8715 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
8716 {
8717         int vi;
8718         int j;
8719         int texturesurfaceindex;
8720         int k;
8721         const msurface_t *surface;
8722         float surfacecolor4f[4];
8723
8724 //      R_Mesh_ResetTextureState();
8725         R_SetupShader_Generic_NoTexture(false, false);
8726
8727         GL_BlendFunc(GL_ONE, GL_ZERO);
8728         GL_DepthMask(writedepth);
8729
8730         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
8731         vi = 0;
8732         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8733         {
8734                 surface = texturesurfacelist[texturesurfaceindex];
8735                 k = (int)(((size_t)surface) / sizeof(msurface_t));
8736                 Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
8737                 for (j = 0;j < surface->num_vertices;j++)
8738                 {
8739                         Vector4Copy(surfacecolor4f, rsurface.batchlightmapcolor4f + 4 * vi);
8740                         vi++;
8741                 }
8742         }
8743         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchlightmapcolor4f, rsurface.batchtexcoordtexture2f);
8744         RSurf_DrawBatch();
8745 }
8746
8747 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass, qboolean ui)
8748 {
8749         CHECKGLERROR
8750         RSurf_SetupDepthAndCulling();
8751         if (r_showsurfaces.integer && r_refdef.view.showdebug)
8752         {
8753                 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
8754                 return;
8755         }
8756         switch (vid.renderpath)
8757         {
8758         case RENDERPATH_GL32:
8759         case RENDERPATH_GLES2:
8760                 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8761                 break;
8762         }
8763         CHECKGLERROR
8764 }
8765
8766 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
8767 {
8768         int i, j;
8769         int texturenumsurfaces, endsurface;
8770         texture_t *texture;
8771         const msurface_t *surface;
8772         const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
8773
8774         RSurf_ActiveModelEntity(ent, true, true, false);
8775
8776         if (r_transparentdepthmasking.integer)
8777         {
8778                 qboolean setup = false;
8779                 for (i = 0;i < numsurfaces;i = j)
8780                 {
8781                         j = i + 1;
8782                         surface = rsurface.modelsurfaces + surfacelist[i];
8783                         texture = surface->texture;
8784                         rsurface.texture = R_GetCurrentTexture(texture);
8785                         rsurface.lightmaptexture = NULL;
8786                         rsurface.deluxemaptexture = NULL;
8787                         rsurface.uselightmaptexture = false;
8788                         // scan ahead until we find a different texture
8789                         endsurface = min(i + 1024, numsurfaces);
8790                         texturenumsurfaces = 0;
8791                         texturesurfacelist[texturenumsurfaces++] = surface;
8792                         for (;j < endsurface;j++)
8793                         {
8794                                 surface = rsurface.modelsurfaces + surfacelist[j];
8795                                 if (texture != surface->texture)
8796                                         break;
8797                                 texturesurfacelist[texturenumsurfaces++] = surface;
8798                         }
8799                         if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
8800                                 continue;
8801                         // render the range of surfaces as depth
8802                         if (!setup)
8803                         {
8804                                 setup = true;
8805                                 GL_ColorMask(0,0,0,0);
8806                                 GL_Color(1,1,1,1);
8807                                 GL_DepthTest(true);
8808                                 GL_BlendFunc(GL_ONE, GL_ZERO);
8809                                 GL_DepthMask(true);
8810 //                              R_Mesh_ResetTextureState();
8811                         }
8812                         RSurf_SetupDepthAndCulling();
8813                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8814                         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8815                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8816                         RSurf_DrawBatch();
8817                 }
8818                 if (setup)
8819                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8820         }
8821
8822         for (i = 0;i < numsurfaces;i = j)
8823         {
8824                 j = i + 1;
8825                 surface = rsurface.modelsurfaces + surfacelist[i];
8826                 texture = surface->texture;
8827                 rsurface.texture = R_GetCurrentTexture(texture);
8828                 // scan ahead until we find a different texture
8829                 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
8830                 texturenumsurfaces = 0;
8831                 texturesurfacelist[texturenumsurfaces++] = surface;
8832                         rsurface.lightmaptexture = surface->lightmaptexture;
8833                         rsurface.deluxemaptexture = surface->deluxemaptexture;
8834                         rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
8835                         for (;j < endsurface;j++)
8836                         {
8837                                 surface = rsurface.modelsurfaces + surfacelist[j];
8838                                 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
8839                                         break;
8840                                 texturesurfacelist[texturenumsurfaces++] = surface;
8841                         }
8842                 // render the range of surfaces
8843                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false, false);
8844         }
8845         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
8846 }
8847
8848 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8849 {
8850         // transparent surfaces get pushed off into the transparent queue
8851         int surfacelistindex;
8852         const msurface_t *surface;
8853         vec3_t tempcenter, center;
8854         for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
8855         {
8856                 surface = texturesurfacelist[surfacelistindex];
8857                 if (r_transparent_sortsurfacesbynearest.integer)
8858                 {
8859                         tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
8860                         tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
8861                         tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
8862                 }
8863                 else
8864                 {
8865                         tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
8866                         tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
8867                         tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
8868                 }
8869                 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
8870                 if (rsurface.entity->transparent_offset) // transparent offset
8871                 {
8872                         center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
8873                         center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
8874                         center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
8875                 }
8876                 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);
8877         }
8878 }
8879
8880 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8881 {
8882         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
8883                 return;
8884         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
8885                 return;
8886         RSurf_SetupDepthAndCulling();
8887         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8888         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8889         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8890         RSurf_DrawBatch();
8891 }
8892
8893 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass, qboolean ui)
8894 {
8895         CHECKGLERROR
8896         if (ui)
8897                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8898         else if (depthonly)
8899                 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
8900         else if (prepass)
8901         {
8902                 if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
8903                         return;
8904                 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8905                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
8906                 else
8907                         R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8908         }
8909         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
8910                 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
8911         else if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
8912                 return;
8913         else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
8914         {
8915                 // in the deferred case, transparent surfaces were queued during prepass
8916                 if (!r_shadow_usingdeferredprepass)
8917                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
8918         }
8919         else
8920         {
8921                 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
8922                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass, ui);
8923         }
8924         CHECKGLERROR
8925 }
8926
8927 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass, qboolean ui)
8928 {
8929         int i, j;
8930         texture_t *texture;
8931         R_FrameData_SetMark();
8932         // break the surface list down into batches by texture and use of lightmapping
8933         for (i = 0;i < numsurfaces;i = j)
8934         {
8935                 j = i + 1;
8936                 // texture is the base texture pointer, rsurface.texture is the
8937                 // current frame/skin the texture is directing us to use (for example
8938                 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
8939                 // use skin 1 instead)
8940                 texture = surfacelist[i]->texture;
8941                 rsurface.texture = R_GetCurrentTexture(texture);
8942                 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
8943                 {
8944                         // if this texture is not the kind we want, skip ahead to the next one
8945                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
8946                                 ;
8947                         continue;
8948                 }
8949                 if(depthonly || prepass)
8950                 {
8951                         rsurface.lightmaptexture = NULL;
8952                         rsurface.deluxemaptexture = NULL;
8953                         rsurface.uselightmaptexture = false;
8954                         // simply scan ahead until we find a different texture or lightmap state
8955                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
8956                                 ;
8957                 }
8958                 else
8959                 {
8960                         rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
8961                         rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
8962                         rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
8963                         // simply scan ahead until we find a different texture or lightmap state
8964                         for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
8965                                 ;
8966                 }
8967                 // render the range of surfaces
8968                 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass, ui);
8969         }
8970         R_FrameData_ReturnToMark();
8971 }
8972
8973 float locboxvertex3f[6*4*3] =
8974 {
8975         1,0,1, 1,0,0, 1,1,0, 1,1,1,
8976         0,1,1, 0,1,0, 0,0,0, 0,0,1,
8977         1,1,1, 1,1,0, 0,1,0, 0,1,1,
8978         0,0,1, 0,0,0, 1,0,0, 1,0,1,
8979         0,0,1, 1,0,1, 1,1,1, 0,1,1,
8980         1,0,0, 0,0,0, 0,1,0, 1,1,0
8981 };
8982
8983 unsigned short locboxelements[6*2*3] =
8984 {
8985          0, 1, 2, 0, 2, 3,
8986          4, 5, 6, 4, 6, 7,
8987          8, 9,10, 8,10,11,
8988         12,13,14, 12,14,15,
8989         16,17,18, 16,18,19,
8990         20,21,22, 20,22,23
8991 };
8992
8993 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
8994 {
8995         int i, j;
8996         cl_locnode_t *loc = (cl_locnode_t *)ent;
8997         vec3_t mins, size;
8998         float vertex3f[6*4*3];
8999         CHECKGLERROR
9000         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9001         GL_DepthMask(false);
9002         GL_DepthRange(0, 1);
9003         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9004         GL_DepthTest(true);
9005         GL_CullFace(GL_NONE);
9006         R_EntityMatrix(&identitymatrix);
9007
9008 //      R_Mesh_ResetTextureState();
9009
9010         i = surfacelist[0];
9011         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9012                          ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9013                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9014                         surfacelist[0] < 0 ? 0.5f : 0.125f);
9015
9016         if (VectorCompare(loc->mins, loc->maxs))
9017         {
9018                 VectorSet(size, 2, 2, 2);
9019                 VectorMA(loc->mins, -0.5f, size, mins);
9020         }
9021         else
9022         {
9023                 VectorCopy(loc->mins, mins);
9024                 VectorSubtract(loc->maxs, loc->mins, size);
9025         }
9026
9027         for (i = 0;i < 6*4*3;)
9028                 for (j = 0;j < 3;j++, i++)
9029                         vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9030
9031         R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9032         R_SetupShader_Generic_NoTexture(false, false);
9033         R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9034 }
9035
9036 void R_DrawLocs(void)
9037 {
9038         int index;
9039         cl_locnode_t *loc, *nearestloc;
9040         vec3_t center;
9041         nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9042         for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9043         {
9044                 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9045                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9046         }
9047 }
9048
9049 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9050 {
9051         if (decalsystem->decals)
9052                 Mem_Free(decalsystem->decals);
9053         memset(decalsystem, 0, sizeof(*decalsystem));
9054 }
9055
9056 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)
9057 {
9058         tridecal_t *decal;
9059         tridecal_t *decals;
9060         int i;
9061
9062         // expand or initialize the system
9063         if (decalsystem->maxdecals <= decalsystem->numdecals)
9064         {
9065                 decalsystem_t old = *decalsystem;
9066                 qboolean useshortelements;
9067                 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9068                 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9069                 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)));
9070                 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9071                 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9072                 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9073                 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9074                 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9075                 if (decalsystem->numdecals)
9076                         memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9077                 if (old.decals)
9078                         Mem_Free(old.decals);
9079                 for (i = 0;i < decalsystem->maxdecals*3;i++)
9080                         decalsystem->element3i[i] = i;
9081                 if (useshortelements)
9082                         for (i = 0;i < decalsystem->maxdecals*3;i++)
9083                                 decalsystem->element3s[i] = i;
9084         }
9085
9086         // grab a decal and search for another free slot for the next one
9087         decals = decalsystem->decals;
9088         decal = decalsystem->decals + (i = decalsystem->freedecal++);
9089         for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9090                 ;
9091         decalsystem->freedecal = i;
9092         if (decalsystem->numdecals <= i)
9093                 decalsystem->numdecals = i + 1;
9094
9095         // initialize the decal
9096         decal->lived = 0;
9097         decal->triangleindex = triangleindex;
9098         decal->surfaceindex = surfaceindex;
9099         decal->decalsequence = decalsequence;
9100         decal->color4f[0][0] = c0[0];
9101         decal->color4f[0][1] = c0[1];
9102         decal->color4f[0][2] = c0[2];
9103         decal->color4f[0][3] = 1;
9104         decal->color4f[1][0] = c1[0];
9105         decal->color4f[1][1] = c1[1];
9106         decal->color4f[1][2] = c1[2];
9107         decal->color4f[1][3] = 1;
9108         decal->color4f[2][0] = c2[0];
9109         decal->color4f[2][1] = c2[1];
9110         decal->color4f[2][2] = c2[2];
9111         decal->color4f[2][3] = 1;
9112         decal->vertex3f[0][0] = v0[0];
9113         decal->vertex3f[0][1] = v0[1];
9114         decal->vertex3f[0][2] = v0[2];
9115         decal->vertex3f[1][0] = v1[0];
9116         decal->vertex3f[1][1] = v1[1];
9117         decal->vertex3f[1][2] = v1[2];
9118         decal->vertex3f[2][0] = v2[0];
9119         decal->vertex3f[2][1] = v2[1];
9120         decal->vertex3f[2][2] = v2[2];
9121         decal->texcoord2f[0][0] = t0[0];
9122         decal->texcoord2f[0][1] = t0[1];
9123         decal->texcoord2f[1][0] = t1[0];
9124         decal->texcoord2f[1][1] = t1[1];
9125         decal->texcoord2f[2][0] = t2[0];
9126         decal->texcoord2f[2][1] = t2[1];
9127         TriangleNormal(v0, v1, v2, decal->plane);
9128         VectorNormalize(decal->plane);
9129         decal->plane[3] = DotProduct(v0, decal->plane);
9130 }
9131
9132 extern cvar_t cl_decals_bias;
9133 extern cvar_t cl_decals_models;
9134 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9135 // baseparms, parms, temps
9136 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)
9137 {
9138         int cornerindex;
9139         int index;
9140         float v[9][3];
9141         const float *vertex3f;
9142         const float *normal3f;
9143         int numpoints;
9144         float points[2][9][3];
9145         float temp[3];
9146         float tc[9][2];
9147         float f;
9148         float c[9][4];
9149         const int *e;
9150
9151         e = rsurface.modelelement3i + 3*triangleindex;
9152
9153         vertex3f = rsurface.modelvertex3f;
9154         normal3f = rsurface.modelnormal3f;
9155
9156         if (normal3f)
9157         {
9158                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9159                 {
9160                         index = 3*e[cornerindex];
9161                         VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9162                 }
9163         }
9164         else
9165         {
9166                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9167                 {
9168                         index = 3*e[cornerindex];
9169                         VectorCopy(vertex3f + index, v[cornerindex]);
9170                 }
9171         }
9172
9173         // cull backfaces
9174         //TriangleNormal(v[0], v[1], v[2], normal);
9175         //if (DotProduct(normal, localnormal) < 0.0f)
9176         //      continue;
9177         // clip by each of the box planes formed from the projection matrix
9178         // if anything survives, we emit the decal
9179         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]);
9180         if (numpoints < 3)
9181                 return;
9182         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]);
9183         if (numpoints < 3)
9184                 return;
9185         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]);
9186         if (numpoints < 3)
9187                 return;
9188         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]);
9189         if (numpoints < 3)
9190                 return;
9191         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]);
9192         if (numpoints < 3)
9193                 return;
9194         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]);
9195         if (numpoints < 3)
9196                 return;
9197         // some part of the triangle survived, so we have to accept it...
9198         if (dynamic)
9199         {
9200                 // dynamic always uses the original triangle
9201                 numpoints = 3;
9202                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9203                 {
9204                         index = 3*e[cornerindex];
9205                         VectorCopy(vertex3f + index, v[cornerindex]);
9206                 }
9207         }
9208         for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9209         {
9210                 // convert vertex positions to texcoords
9211                 Matrix4x4_Transform(projection, v[cornerindex], temp);
9212                 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9213                 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9214                 // calculate distance fade from the projection origin
9215                 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9216                 f = bound(0.0f, f, 1.0f);
9217                 c[cornerindex][0] = r * f;
9218                 c[cornerindex][1] = g * f;
9219                 c[cornerindex][2] = b * f;
9220                 c[cornerindex][3] = 1.0f;
9221                 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9222         }
9223         if (dynamic)
9224                 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);
9225         else
9226                 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9227                         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);
9228 }
9229 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)
9230 {
9231         matrix4x4_t projection;
9232         decalsystem_t *decalsystem;
9233         qboolean dynamic;
9234         dp_model_t *model;
9235         const msurface_t *surface;
9236         const msurface_t *surfaces;
9237         const int *surfacelist;
9238         const texture_t *texture;
9239         int numtriangles;
9240         int numsurfacelist;
9241         int surfacelistindex;
9242         int surfaceindex;
9243         int triangleindex;
9244         float localorigin[3];
9245         float localnormal[3];
9246         float localmins[3];
9247         float localmaxs[3];
9248         float localsize;
9249         //float normal[3];
9250         float planes[6][4];
9251         float angles[3];
9252         bih_t *bih;
9253         int bih_triangles_count;
9254         int bih_triangles[256];
9255         int bih_surfaces[256];
9256
9257         decalsystem = &ent->decalsystem;
9258         model = ent->model;
9259         if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9260         {
9261                 R_DecalSystem_Reset(&ent->decalsystem);
9262                 return;
9263         }
9264
9265         if (!model->brush.data_leafs && !cl_decals_models.integer)
9266         {
9267                 if (decalsystem->model)
9268                         R_DecalSystem_Reset(decalsystem);
9269                 return;
9270         }
9271
9272         if (decalsystem->model != model)
9273                 R_DecalSystem_Reset(decalsystem);
9274         decalsystem->model = model;
9275
9276         RSurf_ActiveModelEntity(ent, true, false, false);
9277
9278         Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9279         Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9280         VectorNormalize(localnormal);
9281         localsize = worldsize*rsurface.inversematrixscale;
9282         localmins[0] = localorigin[0] - localsize;
9283         localmins[1] = localorigin[1] - localsize;
9284         localmins[2] = localorigin[2] - localsize;
9285         localmaxs[0] = localorigin[0] + localsize;
9286         localmaxs[1] = localorigin[1] + localsize;
9287         localmaxs[2] = localorigin[2] + localsize;
9288
9289         //VectorCopy(localnormal, planes[4]);
9290         //VectorVectors(planes[4], planes[2], planes[0]);
9291         AnglesFromVectors(angles, localnormal, NULL, false);
9292         AngleVectors(angles, planes[0], planes[2], planes[4]);
9293         VectorNegate(planes[0], planes[1]);
9294         VectorNegate(planes[2], planes[3]);
9295         VectorNegate(planes[4], planes[5]);
9296         planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9297         planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9298         planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9299         planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9300         planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9301         planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9302
9303 #if 1
9304 // works
9305 {
9306         matrix4x4_t forwardprojection;
9307         Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9308         Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9309 }
9310 #else
9311 // broken
9312 {
9313         float projectionvector[4][3];
9314         VectorScale(planes[0], ilocalsize, projectionvector[0]);
9315         VectorScale(planes[2], ilocalsize, projectionvector[1]);
9316         VectorScale(planes[4], ilocalsize, projectionvector[2]);
9317         projectionvector[0][0] = planes[0][0] * ilocalsize;
9318         projectionvector[0][1] = planes[1][0] * ilocalsize;
9319         projectionvector[0][2] = planes[2][0] * ilocalsize;
9320         projectionvector[1][0] = planes[0][1] * ilocalsize;
9321         projectionvector[1][1] = planes[1][1] * ilocalsize;
9322         projectionvector[1][2] = planes[2][1] * ilocalsize;
9323         projectionvector[2][0] = planes[0][2] * ilocalsize;
9324         projectionvector[2][1] = planes[1][2] * ilocalsize;
9325         projectionvector[2][2] = planes[2][2] * ilocalsize;
9326         projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9327         projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9328         projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9329         Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9330 }
9331 #endif
9332
9333         dynamic = model->surfmesh.isanimated;
9334         numsurfacelist = model->nummodelsurfaces;
9335         surfacelist = model->sortedmodelsurfaces;
9336         surfaces = model->data_surfaces;
9337
9338         bih = NULL;
9339         bih_triangles_count = -1;
9340         if(!dynamic)
9341         {
9342                 if(model->render_bih.numleafs)
9343                         bih = &model->render_bih;
9344                 else if(model->collision_bih.numleafs)
9345                         bih = &model->collision_bih;
9346         }
9347         if(bih)
9348                 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9349         if(bih_triangles_count == 0)
9350                 return;
9351         if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9352                 return;
9353         if(bih_triangles_count > 0)
9354         {
9355                 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9356                 {
9357                         surfaceindex = bih_surfaces[triangleindex];
9358                         surface = surfaces + surfaceindex;
9359                         texture = surface->texture;
9360                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9361                                 continue;
9362                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9363                                 continue;
9364                         R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9365                 }
9366         }
9367         else
9368         {
9369                 for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
9370                 {
9371                         surfaceindex = surfacelist[surfacelistindex];
9372                         surface = surfaces + surfaceindex;
9373                         // check cull box first because it rejects more than any other check
9374                         if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9375                                 continue;
9376                         // skip transparent surfaces
9377                         texture = surface->texture;
9378                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9379                                 continue;
9380                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9381                                 continue;
9382                         numtriangles = surface->num_triangles;
9383                         for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9384                                 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9385                 }
9386         }
9387 }
9388
9389 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9390 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)
9391 {
9392         int renderentityindex;
9393         float worldmins[3];
9394         float worldmaxs[3];
9395         entity_render_t *ent;
9396
9397         worldmins[0] = worldorigin[0] - worldsize;
9398         worldmins[1] = worldorigin[1] - worldsize;
9399         worldmins[2] = worldorigin[2] - worldsize;
9400         worldmaxs[0] = worldorigin[0] + worldsize;
9401         worldmaxs[1] = worldorigin[1] + worldsize;
9402         worldmaxs[2] = worldorigin[2] + worldsize;
9403
9404         R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9405
9406         for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9407         {
9408                 ent = r_refdef.scene.entities[renderentityindex];
9409                 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9410                         continue;
9411
9412                 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9413         }
9414 }
9415
9416 typedef struct r_decalsystem_splatqueue_s
9417 {
9418         vec3_t worldorigin;
9419         vec3_t worldnormal;
9420         float color[4];
9421         float tcrange[4];
9422         float worldsize;
9423         unsigned int decalsequence;
9424 }
9425 r_decalsystem_splatqueue_t;
9426
9427 int r_decalsystem_numqueued = 0;
9428 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9429
9430 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)
9431 {
9432         r_decalsystem_splatqueue_t *queue;
9433
9434         if (r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9435                 return;
9436
9437         queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9438         VectorCopy(worldorigin, queue->worldorigin);
9439         VectorCopy(worldnormal, queue->worldnormal);
9440         Vector4Set(queue->color, r, g, b, a);
9441         Vector4Set(queue->tcrange, s1, t1, s2, t2);
9442         queue->worldsize = worldsize;
9443         queue->decalsequence = cl.decalsequence++;
9444 }
9445
9446 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9447 {
9448         int i;
9449         r_decalsystem_splatqueue_t *queue;
9450
9451         for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9452                 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);
9453         r_decalsystem_numqueued = 0;
9454 }
9455
9456 extern cvar_t cl_decals_max;
9457 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9458 {
9459         int i;
9460         decalsystem_t *decalsystem = &ent->decalsystem;
9461         int numdecals;
9462         unsigned int killsequence;
9463         tridecal_t *decal;
9464         float frametime;
9465         float lifetime;
9466
9467         if (!decalsystem->numdecals)
9468                 return;
9469
9470         if (r_showsurfaces.integer)
9471                 return;
9472
9473         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9474         {
9475                 R_DecalSystem_Reset(decalsystem);
9476                 return;
9477         }
9478
9479         killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9480         lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9481
9482         if (decalsystem->lastupdatetime)
9483                 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9484         else
9485                 frametime = 0;
9486         decalsystem->lastupdatetime = r_refdef.scene.time;
9487         numdecals = decalsystem->numdecals;
9488
9489         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9490         {
9491                 if (decal->color4f[0][3])
9492                 {
9493                         decal->lived += frametime;
9494                         if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9495                         {
9496                                 memset(decal, 0, sizeof(*decal));
9497                                 if (decalsystem->freedecal > i)
9498                                         decalsystem->freedecal = i;
9499                         }
9500                 }
9501         }
9502         decal = decalsystem->decals;
9503         while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9504                 numdecals--;
9505
9506         // collapse the array by shuffling the tail decals into the gaps
9507         for (;;)
9508         {
9509                 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
9510                         decalsystem->freedecal++;
9511                 if (decalsystem->freedecal == numdecals)
9512                         break;
9513                 decal[decalsystem->freedecal] = decal[--numdecals];
9514         }
9515
9516         decalsystem->numdecals = numdecals;
9517
9518         if (numdecals <= 0)
9519         {
9520                 // if there are no decals left, reset decalsystem
9521                 R_DecalSystem_Reset(decalsystem);
9522         }
9523 }
9524
9525 extern skinframe_t *decalskinframe;
9526 static void R_DrawModelDecals_Entity(entity_render_t *ent)
9527 {
9528         int i;
9529         decalsystem_t *decalsystem = &ent->decalsystem;
9530         int numdecals;
9531         tridecal_t *decal;
9532         float faderate;
9533         float alpha;
9534         float *v3f;
9535         float *c4f;
9536         float *t2f;
9537         const int *e;
9538         const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
9539         int numtris = 0;
9540
9541         numdecals = decalsystem->numdecals;
9542         if (!numdecals)
9543                 return;
9544
9545         if (r_showsurfaces.integer)
9546                 return;
9547
9548         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9549         {
9550                 R_DecalSystem_Reset(decalsystem);
9551                 return;
9552         }
9553
9554         // if the model is static it doesn't matter what value we give for
9555         // wantnormals and wanttangents, so this logic uses only rules applicable
9556         // to a model, knowing that they are meaningless otherwise
9557         RSurf_ActiveModelEntity(ent, false, false, false);
9558
9559         decalsystem->lastupdatetime = r_refdef.scene.time;
9560
9561         faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
9562
9563         // update vertex positions for animated models
9564         v3f = decalsystem->vertex3f;
9565         c4f = decalsystem->color4f;
9566         t2f = decalsystem->texcoord2f;
9567         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9568         {
9569                 if (!decal->color4f[0][3])
9570                         continue;
9571
9572                 if (surfacevisible && !surfacevisible[decal->surfaceindex])
9573                         continue;
9574
9575                 // skip backfaces
9576                 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
9577                         continue;
9578
9579                 // update color values for fading decals
9580                 if (decal->lived >= cl_decals_time.value)
9581                         alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
9582                 else
9583                         alpha = 1.0f;
9584
9585                 c4f[ 0] = decal->color4f[0][0] * alpha;
9586                 c4f[ 1] = decal->color4f[0][1] * alpha;
9587                 c4f[ 2] = decal->color4f[0][2] * alpha;
9588                 c4f[ 3] = 1;
9589                 c4f[ 4] = decal->color4f[1][0] * alpha;
9590                 c4f[ 5] = decal->color4f[1][1] * alpha;
9591                 c4f[ 6] = decal->color4f[1][2] * alpha;
9592                 c4f[ 7] = 1;
9593                 c4f[ 8] = decal->color4f[2][0] * alpha;
9594                 c4f[ 9] = decal->color4f[2][1] * alpha;
9595                 c4f[10] = decal->color4f[2][2] * alpha;
9596                 c4f[11] = 1;
9597
9598                 t2f[0] = decal->texcoord2f[0][0];
9599                 t2f[1] = decal->texcoord2f[0][1];
9600                 t2f[2] = decal->texcoord2f[1][0];
9601                 t2f[3] = decal->texcoord2f[1][1];
9602                 t2f[4] = decal->texcoord2f[2][0];
9603                 t2f[5] = decal->texcoord2f[2][1];
9604
9605                 // update vertex positions for animated models
9606                 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
9607                 {
9608                         e = rsurface.modelelement3i + 3*decal->triangleindex;
9609                         VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
9610                         VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
9611                         VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
9612                 }
9613                 else
9614                 {
9615                         VectorCopy(decal->vertex3f[0], v3f);
9616                         VectorCopy(decal->vertex3f[1], v3f + 3);
9617                         VectorCopy(decal->vertex3f[2], v3f + 6);
9618                 }
9619
9620                 if (r_refdef.fogenabled)
9621                 {
9622                         alpha = RSurf_FogVertex(v3f);
9623                         VectorScale(c4f, alpha, c4f);
9624                         alpha = RSurf_FogVertex(v3f + 3);
9625                         VectorScale(c4f + 4, alpha, c4f + 4);
9626                         alpha = RSurf_FogVertex(v3f + 6);
9627                         VectorScale(c4f + 8, alpha, c4f + 8);
9628                 }
9629
9630                 v3f += 9;
9631                 c4f += 12;
9632                 t2f += 6;
9633                 numtris++;
9634         }
9635
9636         if (numtris > 0)
9637         {
9638                 r_refdef.stats[r_stat_drawndecals] += numtris;
9639
9640                 // now render the decals all at once
9641                 // (this assumes they all use one particle font texture!)
9642                 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);
9643 //              R_Mesh_ResetTextureState();
9644                 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
9645                 GL_DepthMask(false);
9646                 GL_DepthRange(0, 1);
9647                 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
9648                 GL_DepthTest(true);
9649                 GL_CullFace(GL_NONE);
9650                 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
9651                 R_SetupShader_Generic(decalskinframe->base, false, false, false);
9652                 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
9653         }
9654 }
9655
9656 static void R_DrawModelDecals(void)
9657 {
9658         int i, numdecals;
9659
9660         // fade faster when there are too many decals
9661         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9662         for (i = 0;i < r_refdef.scene.numentities;i++)
9663                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9664
9665         R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
9666         for (i = 0;i < r_refdef.scene.numentities;i++)
9667                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9668                         R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
9669
9670         R_DecalSystem_ApplySplatEntitiesQueue();
9671
9672         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9673         for (i = 0;i < r_refdef.scene.numentities;i++)
9674                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9675
9676         r_refdef.stats[r_stat_totaldecals] += numdecals;
9677
9678         if (r_showsurfaces.integer || !r_drawdecals.integer)
9679                 return;
9680
9681         R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
9682
9683         for (i = 0;i < r_refdef.scene.numentities;i++)
9684         {
9685                 if (!r_refdef.viewcache.entityvisible[i])
9686                         continue;
9687                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9688                         R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
9689         }
9690 }
9691
9692 extern cvar_t mod_collision_bih;
9693 static void R_DrawDebugModel(void)
9694 {
9695         entity_render_t *ent = rsurface.entity;
9696         int i, j, flagsmask;
9697         const msurface_t *surface;
9698         dp_model_t *model = ent->model;
9699
9700         if (!sv.active  && !cls.demoplayback && ent != r_refdef.scene.worldentity)
9701                 return;
9702
9703         if (r_showoverdraw.value > 0)
9704         {
9705                 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
9706                 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9707                 R_SetupShader_Generic_NoTexture(false, false);
9708                 GL_DepthTest(false);
9709                 GL_DepthMask(false);
9710                 GL_DepthRange(0, 1);
9711                 GL_BlendFunc(GL_ONE, GL_ONE);
9712                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9713                 {
9714                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9715                                 continue;
9716                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9717                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9718                         {
9719                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
9720                                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
9721                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9722                                         GL_Color(c, 0, 0, 1.0f);
9723                                 else if (ent == r_refdef.scene.worldentity)
9724                                         GL_Color(c, c, c, 1.0f);
9725                                 else
9726                                         GL_Color(0, c, 0, 1.0f);
9727                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9728                                 RSurf_DrawBatch();
9729                         }
9730                 }
9731                 rsurface.texture = NULL;
9732         }
9733
9734         flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9735
9736 //      R_Mesh_ResetTextureState();
9737         R_SetupShader_Generic_NoTexture(false, false);
9738         GL_DepthRange(0, 1);
9739         GL_DepthTest(!r_showdisabledepthtest.integer);
9740         GL_DepthMask(false);
9741         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9742
9743         if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
9744         {
9745                 int triangleindex;
9746                 int bihleafindex;
9747                 qboolean cullbox = false;
9748                 const q3mbrush_t *brush;
9749                 const bih_t *bih = &model->collision_bih;
9750                 const bih_leaf_t *bihleaf;
9751                 float vertex3f[3][3];
9752                 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
9753                 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
9754                 {
9755                         if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
9756                                 continue;
9757                         switch (bihleaf->type)
9758                         {
9759                         case BIH_BRUSH:
9760                                 brush = model->brush.data_brushes + bihleaf->itemindex;
9761                                 if (brush->colbrushf && brush->colbrushf->numtriangles)
9762                                 {
9763                                         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);
9764                                         R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
9765                                         R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
9766                                 }
9767                                 break;
9768                         case BIH_COLLISIONTRIANGLE:
9769                                 triangleindex = bihleaf->itemindex;
9770                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
9771                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
9772                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
9773                                 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);
9774                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9775                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9776                                 break;
9777                         case BIH_RENDERTRIANGLE:
9778                                 triangleindex = bihleaf->itemindex;
9779                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
9780                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
9781                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
9782                                 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);
9783                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9784                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9785                                 break;
9786                         }
9787                 }
9788         }
9789
9790         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9791
9792 #ifndef USE_GLES2
9793         if (r_showtris.value > 0 && qglPolygonMode)
9794         {
9795                 if (r_showdisabledepthtest.integer)
9796                 {
9797                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9798                         GL_DepthMask(false);
9799                 }
9800                 else
9801                 {
9802                         GL_BlendFunc(GL_ONE, GL_ZERO);
9803                         GL_DepthMask(true);
9804                 }
9805                 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
9806                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9807                 {
9808                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9809                                 continue;
9810                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9811                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9812                         {
9813                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9814                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9815                                         GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
9816                                 else if (ent == r_refdef.scene.worldentity)
9817                                         GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
9818                                 else
9819                                         GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
9820                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9821                                 RSurf_DrawBatch();
9822                         }
9823                 }
9824                 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
9825                 rsurface.texture = NULL;
9826         }
9827
9828 # if 0
9829         // FIXME!  implement r_shownormals with just triangles
9830         if (r_shownormals.value != 0 && qglBegin)
9831         {
9832                 int l, k;
9833                 vec3_t v;
9834                 if (r_showdisabledepthtest.integer)
9835                 {
9836                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9837                         GL_DepthMask(false);
9838                 }
9839                 else
9840                 {
9841                         GL_BlendFunc(GL_ONE, GL_ZERO);
9842                         GL_DepthMask(true);
9843                 }
9844                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9845                 {
9846                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9847                                 continue;
9848                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9849                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9850                         {
9851                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9852                                 qglBegin(GL_LINES);
9853                                 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
9854                                 {
9855                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9856                                         {
9857                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9858                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9859                                                 qglVertex3f(v[0], v[1], v[2]);
9860                                                 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9861                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9862                                                 qglVertex3f(v[0], v[1], v[2]);
9863                                         }
9864                                 }
9865                                 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
9866                                 {
9867                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9868                                         {
9869                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9870                                                 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
9871                                                 qglVertex3f(v[0], v[1], v[2]);
9872                                                 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
9873                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9874                                                 qglVertex3f(v[0], v[1], v[2]);
9875                                         }
9876                                 }
9877                                 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
9878                                 {
9879                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9880                                         {
9881                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9882                                                 GL_Color(0, r_refdef.view.colorscale, 0, 1);
9883                                                 qglVertex3f(v[0], v[1], v[2]);
9884                                                 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
9885                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9886                                                 qglVertex3f(v[0], v[1], v[2]);
9887                                         }
9888                                 }
9889                                 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
9890                                 {
9891                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9892                                         {
9893                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9894                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9895                                                 qglVertex3f(v[0], v[1], v[2]);
9896                                                 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9897                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9898                                                 qglVertex3f(v[0], v[1], v[2]);
9899                                         }
9900                                 }
9901                                 qglEnd();
9902                                 CHECKGLERROR
9903                         }
9904                 }
9905                 rsurface.texture = NULL;
9906         }
9907 # endif
9908 #endif
9909 }
9910
9911 int r_maxsurfacelist = 0;
9912 const msurface_t **r_surfacelist = NULL;
9913 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass, qboolean ui)
9914 {
9915         int i, j, endj, flagsmask;
9916         dp_model_t *model = ent->model;
9917         msurface_t *surfaces;
9918         unsigned char *update;
9919         int numsurfacelist = 0;
9920         if (model == NULL)
9921                 return;
9922
9923         if (r_maxsurfacelist < model->num_surfaces)
9924         {
9925                 r_maxsurfacelist = model->num_surfaces;
9926                 if (r_surfacelist)
9927                         Mem_Free((msurface_t **)r_surfacelist);
9928                 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
9929         }
9930
9931         if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
9932                 RSurf_ActiveModelEntity(ent, false, false, false);
9933         else if (prepass)
9934                 RSurf_ActiveModelEntity(ent, true, true, true);
9935         else if (depthonly)
9936                 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
9937         else
9938                 RSurf_ActiveModelEntity(ent, true, true, false);
9939
9940         surfaces = model->data_surfaces;
9941         update = model->brushq1.lightmapupdateflags;
9942
9943         // update light styles
9944         if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0)
9945         {
9946                 model_brush_lightstyleinfo_t *style;
9947                 for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
9948                 {
9949                         if (style->value != r_refdef.scene.lightstylevalue[style->style])
9950                         {
9951                                 int *list = style->surfacelist;
9952                                 style->value = r_refdef.scene.lightstylevalue[style->style];
9953                                 for (j = 0;j < style->numsurfaces;j++)
9954                                         update[list[j]] = true;
9955                         }
9956                 }
9957         }
9958
9959         flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
9960
9961         if (debug)
9962         {
9963                 R_DrawDebugModel();
9964                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
9965                 return;
9966         }
9967
9968         rsurface.lightmaptexture = NULL;
9969         rsurface.deluxemaptexture = NULL;
9970         rsurface.uselightmaptexture = false;
9971         rsurface.texture = NULL;
9972         rsurface.rtlight = NULL;
9973         numsurfacelist = 0;
9974         // add visible surfaces to draw list
9975         if (ent == r_refdef.scene.worldentity)
9976         {
9977                 // for the world entity, check surfacevisible
9978                 for (i = 0;i < model->nummodelsurfaces;i++)
9979                 {
9980                         j = model->sortedmodelsurfaces[i];
9981                         if (r_refdef.viewcache.world_surfacevisible[j])
9982                                 r_surfacelist[numsurfacelist++] = surfaces + j;
9983                 }
9984         }
9985         else if (ui)
9986         {
9987                 // for ui we have to preserve the order of surfaces
9988                 for (i = 0; i < model->nummodelsurfaces; i++)
9989                         r_surfacelist[numsurfacelist++] = surfaces + model->firstmodelsurface + i;
9990         }
9991         else
9992         {
9993                 // add all surfaces
9994                 for (i = 0; i < model->nummodelsurfaces; i++)
9995                         r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
9996         }
9997         // don't do anything if there were no surfaces
9998         if (!numsurfacelist)
9999         {
10000                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10001                 return;
10002         }
10003         // update lightmaps if needed
10004         if (update)
10005         {
10006                 int updated = 0;
10007                 for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
10008                 {
10009                         if (update[j])
10010                         {
10011                                 updated++;
10012                                 R_BuildLightMap(ent, surfaces + j);
10013                         }
10014                 }
10015         }
10016
10017         R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass, ui);
10018
10019         // add to stats if desired
10020         if (r_speeds.integer && !skysurfaces && !depthonly)
10021         {
10022                 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10023                 for (j = 0;j < numsurfacelist;j++)
10024                         r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10025         }
10026
10027         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10028 }
10029
10030 void R_DebugLine(vec3_t start, vec3_t end)
10031 {
10032         dp_model_t *mod = CL_Mesh_UI();
10033         msurface_t *surf;
10034         int e0, e1, e2, e3;
10035         float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10036         float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10037         float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10038         vec4_t w[2], s[2];
10039
10040         // transform to screen coords first
10041         Vector4Set(w[0], start[0], start[1], start[2], 1);
10042         Vector4Set(w[1], end[0], end[1], end[2], 1);
10043         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10044         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10045         x1 = s[0][0] * vid_conwidth.value / vid.width;
10046         y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10047         x2 = s[1][0] * vid_conwidth.value / vid.width;
10048         y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10049         //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10050
10051         // add the line to the UI mesh for drawing later
10052
10053         // width is measured in real pixels
10054         if (fabs(x2 - x1) > fabs(y2 - y1))
10055         {
10056                 offsetx = 0;
10057                 offsety = 0.5f * width * vid_conheight.value / vid.height;
10058         }
10059         else
10060         {
10061                 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10062                 offsety = 0;
10063         }
10064         surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_WALL | MATERIALFLAG_VERTEXCOLOR | MATERIALFLAG_ALPHAGEN_VERTEX), true);
10065         e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10066         e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10067         e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10068         e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10069         Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10070         Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10071
10072 }
10073
10074
10075 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)
10076 {
10077         static texture_t texture;
10078
10079         // fake enough texture and surface state to render this geometry
10080
10081         texture.update_lastrenderframe = -1; // regenerate this texture
10082         texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10083         texture.basealpha = 1.0f;
10084         texture.currentskinframe = skinframe;
10085         texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10086         texture.offsetmapping = OFFSETMAPPING_OFF;
10087         texture.offsetscale = 1;
10088         texture.specularscalemod = 1;
10089         texture.specularpowermod = 1;
10090         texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10091
10092         R_DrawCustomSurface_Texture(&texture, texmatrix, materialflags, firstvertex, numvertices, firsttriangle, numtriangles, writedepth, prepass, ui);
10093 }
10094
10095 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)
10096 {
10097         static msurface_t surface;
10098         const msurface_t *surfacelist = &surface;
10099
10100         // fake enough texture and surface state to render this geometry
10101         surface.texture = texture;
10102         surface.num_triangles = numtriangles;
10103         surface.num_firsttriangle = firsttriangle;
10104         surface.num_vertices = numvertices;
10105         surface.num_firstvertex = firstvertex;
10106
10107         // now render it
10108         rsurface.texture = R_GetCurrentTexture(surface.texture);
10109         rsurface.lightmaptexture = NULL;
10110         rsurface.deluxemaptexture = NULL;
10111         rsurface.uselightmaptexture = false;
10112         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass, ui);
10113 }