]> git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
Implement chromatic aberration, configurable with r_colorfringe cvar.
[xonotic/darkplaces.git] / gl_rmain.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_main.c
21
22 #include "quakedef.h"
23 #include "r_shadow.h"
24 #include "polygon.h"
25 #include "image.h"
26 #include "ft2.h"
27 #include "csprogs.h"
28 #include "cl_video.h"
29 #include "cl_collision.h"
30
31 #ifdef WIN32
32 // Enable NVIDIA High Performance Graphics while using Integrated Graphics.
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36 __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
37 #ifdef __cplusplus
38 }
39 #endif
40 #endif
41
42 mempool_t *r_main_mempool;
43 rtexturepool_t *r_main_texturepool;
44
45 int r_textureframe = 0; ///< used only by R_GetCurrentTexture, incremented per view and per UI render
46
47 static qboolean r_loadnormalmap;
48 static qboolean r_loadgloss;
49 qboolean r_loadfog;
50 static qboolean r_loaddds;
51 static qboolean r_savedds;
52 static qboolean r_gpuskeletal;
53
54 //
55 // screen size info
56 //
57 r_refdef_t r_refdef;
58
59 cvar_t r_motionblur = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur", "0", "screen motionblur - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
60 cvar_t r_damageblur = {CVAR_CLIENT | CVAR_SAVE, "r_damageblur", "0", "screen motionblur based on damage - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
61 cvar_t r_motionblur_averaging = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_averaging", "0.1", "sliding average reaction time for velocity (higher = slower adaption to change)"};
62 cvar_t r_motionblur_randomize = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"};
63 cvar_t r_motionblur_minblur = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_minblur", "0.5", "factor of blur to apply at all times (always have this amount of blur no matter what the other factors are)"};
64 cvar_t r_motionblur_maxblur = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_maxblur", "0.9", "maxmimum amount of blur"};
65 cvar_t r_motionblur_velocityfactor = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_velocityfactor", "1", "factoring in of player velocity to the blur equation - the faster the player moves around the map, the more blur they get"};
66 cvar_t r_motionblur_velocityfactor_minspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_velocityfactor_minspeed", "400", "lower value of velocity when it starts to factor into blur equation"};
67 cvar_t r_motionblur_velocityfactor_maxspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_velocityfactor_maxspeed", "800", "upper value of velocity when it reaches the peak factor into blur equation"};
68 cvar_t r_motionblur_mousefactor = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_mousefactor", "2", "factoring in of mouse acceleration to the blur equation - the faster the player turns their mouse, the more blur they get"};
69 cvar_t r_motionblur_mousefactor_minspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_mousefactor_minspeed", "0", "lower value of mouse acceleration when it starts to factor into blur equation"};
70 cvar_t r_motionblur_mousefactor_maxspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_mousefactor_maxspeed", "50", "upper value of mouse acceleration when it reaches the peak factor into blur equation"};
71
72 cvar_t r_depthfirst = {CVAR_CLIENT | CVAR_SAVE, "r_depthfirst", "0", "renders a depth-only version of the scene before normal rendering begins to eliminate overdraw, values: 0 = off, 1 = world depth, 2 = world and model depth"};
73 cvar_t r_useinfinitefarclip = {CVAR_CLIENT | CVAR_SAVE, "r_useinfinitefarclip", "1", "enables use of a special kind of projection matrix that has an extremely large farclip"};
74 cvar_t r_farclip_base = {CVAR_CLIENT, "r_farclip_base", "65536", "farclip (furthest visible distance) for rendering when r_useinfinitefarclip is 0"};
75 cvar_t r_farclip_world = {CVAR_CLIENT, "r_farclip_world", "2", "adds map size to farclip multiplied by this value"};
76 cvar_t r_nearclip = {CVAR_CLIENT, "r_nearclip", "1", "distance from camera of nearclip plane" };
77 cvar_t r_deformvertexes = {CVAR_CLIENT, "r_deformvertexes", "1", "allows use of deformvertexes in shader files (can be turned off to check performance impact)"};
78 cvar_t r_transparent = {CVAR_CLIENT, "r_transparent", "1", "allows use of transparent surfaces (can be turned off to check performance impact)"};
79 cvar_t r_transparent_alphatocoverage = {CVAR_CLIENT, "r_transparent_alphatocoverage", "1", "enables GL_ALPHA_TO_COVERAGE antialiasing technique on alphablend and alphatest surfaces when using vid_samples 2 or higher"};
80 cvar_t r_transparent_sortsurfacesbynearest = {CVAR_CLIENT, "r_transparent_sortsurfacesbynearest", "1", "sort entity and world surfaces by nearest point on bounding box instead of using the center of the bounding box, usually reduces sorting artifacts"};
81 cvar_t r_transparent_useplanardistance = {CVAR_CLIENT, "r_transparent_useplanardistance", "0", "sort transparent meshes by distance from view plane rather than spherical distance to the chosen point"};
82 cvar_t r_showoverdraw = {CVAR_CLIENT, "r_showoverdraw", "0", "shows overlapping geometry"};
83 cvar_t r_showbboxes = {CVAR_CLIENT, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
84 cvar_t r_showbboxes_client = {CVAR_CLIENT, "r_showbboxes_client", "0", "shows bounding boxes of clientside qc entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
85 cvar_t r_showsurfaces = {CVAR_CLIENT, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 2 shows triangle draw order (for analyzing whether meshes are optimized for vertex cache)"};
86 cvar_t r_showtris = {CVAR_CLIENT, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
87 cvar_t r_shownormals = {CVAR_CLIENT, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
88 cvar_t r_showlighting = {CVAR_CLIENT, "r_showlighting", "0", "shows areas lit by lights, useful for finding out why some areas of a map render slowly (bright orange = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
89 cvar_t r_showcollisionbrushes = {CVAR_CLIENT, "r_showcollisionbrushes", "0", "draws collision brushes in quake3 maps (mode 1), mode 2 disables rendering of world (trippy!)"};
90 cvar_t r_showcollisionbrushes_polygonfactor = {CVAR_CLIENT, "r_showcollisionbrushes_polygonfactor", "-1", "expands outward the brush polygons a little bit, used to make collision brushes appear infront of walls"};
91 cvar_t r_showcollisionbrushes_polygonoffset = {CVAR_CLIENT, "r_showcollisionbrushes_polygonoffset", "0", "nudges brush polygon depth in hardware depth units, used to make collision brushes appear infront of walls"};
92 cvar_t r_showdisabledepthtest = {CVAR_CLIENT, "r_showdisabledepthtest", "0", "disables depth testing on r_show* cvars, allowing you to see what hidden geometry the graphics card is processing"};
93 cvar_t r_showspriteedges = {CVAR_CLIENT, "r_showspriteedges", "0", "renders a debug outline to show the polygon shape of each sprite frame rendered (may be 2 or more in case of interpolated animations), for debugging rendering bugs with specific view types"};
94 cvar_t r_showparticleedges = {CVAR_CLIENT, "r_showparticleedges", "0", "renders a debug outline to show the polygon shape of each particle, for debugging rendering bugs with specific view types"};
95 cvar_t r_drawportals = {CVAR_CLIENT, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
96 cvar_t r_drawentities = {CVAR_CLIENT, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
97 cvar_t r_draw2d = {CVAR_CLIENT, "r_draw2d","1", "draw 2D stuff (dangerous to turn off)"};
98 cvar_t r_drawworld = {CVAR_CLIENT, "r_drawworld","1", "draw world (most static stuff)"};
99 cvar_t r_drawviewmodel = {CVAR_CLIENT, "r_drawviewmodel","1", "draw your weapon model"};
100 cvar_t r_drawexteriormodel = {CVAR_CLIENT, "r_drawexteriormodel","1", "draw your player model (e.g. in chase cam, reflections)"};
101 cvar_t r_cullentities_trace = {CVAR_CLIENT, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
102 cvar_t r_cullentities_trace_entityocclusion = {CVAR_CLIENT, "r_cullentities_trace_entityocclusion", "1", "check for occluding entities such as doors, not just world hull"};
103 cvar_t r_cullentities_trace_samples = {CVAR_CLIENT, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling (in addition to center sample)"};
104 cvar_t r_cullentities_trace_tempentitysamples = {CVAR_CLIENT, "r_cullentities_trace_tempentitysamples", "-1", "number of samples to test for entity culling of temp entities (including all CSQC entities), -1 disables trace culling on these entities to prevent flicker (pvs still applies)"};
105 cvar_t r_cullentities_trace_enlarge = {CVAR_CLIENT, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
106 cvar_t r_cullentities_trace_expand = {CVAR_CLIENT, "r_cullentities_trace_expand", "0", "box expanded by this many units for entity culling"};
107 cvar_t r_cullentities_trace_pad = {CVAR_CLIENT, "r_cullentities_trace_pad", "8", "accept traces that hit within this many units of the box"};
108 cvar_t r_cullentities_trace_delay = {CVAR_CLIENT, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
109 cvar_t r_cullentities_trace_eyejitter = {CVAR_CLIENT, "r_cullentities_trace_eyejitter", "16", "randomly offset rays from the eye by this much to reduce the odds of flickering"};
110 cvar_t r_sortentities = {CVAR_CLIENT, "r_sortentities", "0", "sort entities before drawing (might be faster)"};
111 cvar_t r_speeds = {CVAR_CLIENT, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
112 cvar_t r_fullbright = {CVAR_CLIENT, "r_fullbright","0", "makes map very bright and renders faster"};
113
114 cvar_t r_fullbright_directed = {CVAR_CLIENT, "r_fullbright_directed", "0", "render fullbright things (unlit worldmodel and EF_FULLBRIGHT entities, but not fullbright shaders) using a constant light direction instead to add more depth while keeping uniform brightness"};
115 cvar_t r_fullbright_directed_ambient = {CVAR_CLIENT, "r_fullbright_directed_ambient", "0.5", "ambient light multiplier for directed fullbright"};
116 cvar_t r_fullbright_directed_diffuse = {CVAR_CLIENT, "r_fullbright_directed_diffuse", "0.75", "diffuse light multiplier for directed fullbright"};
117 cvar_t r_fullbright_directed_pitch = {CVAR_CLIENT, "r_fullbright_directed_pitch", "20", "constant pitch direction ('height') of the fake light source to use for fullbright"};
118 cvar_t r_fullbright_directed_pitch_relative = {CVAR_CLIENT, "r_fullbright_directed_pitch_relative", "0", "whether r_fullbright_directed_pitch is interpreted as absolute (0) or relative (1) pitch"};
119
120 cvar_t r_wateralpha = {CVAR_CLIENT | CVAR_SAVE, "r_wateralpha","1", "opacity of water polygons"};
121 cvar_t r_dynamic = {CVAR_CLIENT | CVAR_SAVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
122 cvar_t r_fullbrights = {CVAR_CLIENT | CVAR_SAVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
123 cvar_t r_shadows = {CVAR_CLIENT | CVAR_SAVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this); when set to 2, always cast the shadows in the direction set by r_shadows_throwdirection, otherwise use the model lighting."};
124 cvar_t r_shadows_darken = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_darken", "0.5", "how much shadowed areas will be darkened"};
125 cvar_t r_shadows_throwdistance = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
126 cvar_t r_shadows_throwdirection = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_throwdirection", "0 0 -1", "override throwing direction for r_shadows 2"};
127 cvar_t r_shadows_drawafterrtlighting = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_drawafterrtlighting", "0", "draw fake shadows AFTER realtime lightning is drawn. May be useful for simulating fast sunlight on large outdoor maps with only one noshadow rtlight. The price is less realistic appearance of dynamic light shadows."};
128 cvar_t r_shadows_castfrombmodels = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
129 cvar_t r_shadows_focus = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_focus", "0 0 0", "offset the shadowed area focus"};
130 cvar_t r_shadows_shadowmapscale = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_shadowmapscale", "0.25", "higher values increase shadowmap quality at a cost of area covered (multiply global shadowmap precision) for fake shadows. Needs shadowmapping ON."};
131 cvar_t r_shadows_shadowmapbias = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_shadowmapbias", "-1", "sets shadowmap bias for fake shadows. -1 sets the value of r_shadow_shadowmapping_bias. Needs shadowmapping ON."};
132 cvar_t r_q1bsp_skymasking = {CVAR_CLIENT, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
133 cvar_t r_polygonoffset_submodel_factor = {CVAR_CLIENT, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
134 cvar_t r_polygonoffset_submodel_offset = {CVAR_CLIENT, "r_polygonoffset_submodel_offset", "14", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
135 cvar_t r_polygonoffset_decals_factor = {CVAR_CLIENT, "r_polygonoffset_decals_factor", "0", "biases depth values of decals to prevent z-fighting artifacts"};
136 cvar_t r_polygonoffset_decals_offset = {CVAR_CLIENT, "r_polygonoffset_decals_offset", "-14", "biases depth values of decals to prevent z-fighting artifacts"};
137 cvar_t r_fog_exp2 = {CVAR_CLIENT, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"};
138 cvar_t r_fog_clear = {CVAR_CLIENT, "r_fog_clear", "1", "clears renderbuffer with fog color before render starts"};
139 cvar_t r_drawfog = {CVAR_CLIENT | CVAR_SAVE, "r_drawfog", "1", "allows one to disable fog rendering"};
140 cvar_t r_transparentdepthmasking = {CVAR_CLIENT | CVAR_SAVE, "r_transparentdepthmasking", "0", "enables depth writes on transparent meshes whose materially is normally opaque, this prevents seeing the inside of a transparent mesh"};
141 cvar_t r_transparent_sortmindist = {CVAR_CLIENT | CVAR_SAVE, "r_transparent_sortmindist", "0", "lower distance limit for transparent sorting"};
142 cvar_t r_transparent_sortmaxdist = {CVAR_CLIENT | CVAR_SAVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"};
143 cvar_t r_transparent_sortarraysize = {CVAR_CLIENT | CVAR_SAVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"};
144 cvar_t r_celshading = {CVAR_CLIENT | CVAR_SAVE, "r_celshading", "0", "cartoon-style light shading (OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9
145 cvar_t r_celoutlines = {CVAR_CLIENT | CVAR_SAVE, "r_celoutlines", "0", "cartoon-style outlines (requires r_shadow_deferred; OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9
146
147 cvar_t gl_fogenable = {CVAR_CLIENT, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
148 cvar_t gl_fogdensity = {CVAR_CLIENT, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
149 cvar_t gl_fogred = {CVAR_CLIENT, "gl_fogred","0.3", "nehahra fog color red value (for Nehahra compatibility only)"};
150 cvar_t gl_foggreen = {CVAR_CLIENT, "gl_foggreen","0.3", "nehahra fog color green value (for Nehahra compatibility only)"};
151 cvar_t gl_fogblue = {CVAR_CLIENT, "gl_fogblue","0.3", "nehahra fog color blue value (for Nehahra compatibility only)"};
152 cvar_t gl_fogstart = {CVAR_CLIENT, "gl_fogstart", "0", "nehahra fog start distance (for Nehahra compatibility only)"};
153 cvar_t gl_fogend = {CVAR_CLIENT, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
154 cvar_t gl_skyclip = {CVAR_CLIENT, "gl_skyclip", "4608", "nehahra farclip distance - the real fog end (for Nehahra compatibility only)"};
155
156 cvar_t r_texture_dds_load = {CVAR_CLIENT | CVAR_SAVE, "r_texture_dds_load", "0", "load compressed dds/filename.dds texture instead of filename.tga, if the file exists (requires driver support)"};
157 cvar_t r_texture_dds_save = {CVAR_CLIENT | CVAR_SAVE, "r_texture_dds_save", "0", "save compressed dds/filename.dds texture when filename.tga is loaded, so that it can be loaded instead next time"};
158
159 cvar_t r_textureunits = {CVAR_CLIENT, "r_textureunits", "32", "number of texture units to use in GL 1.1 and GL 1.3 rendering paths"};
160 static cvar_t gl_combine = {CVAR_CLIENT | CVAR_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"};
161 static cvar_t r_glsl = {CVAR_CLIENT | CVAR_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"};
162
163 cvar_t r_usedepthtextures = {CVAR_CLIENT | CVAR_SAVE, "r_usedepthtextures", "1", "use depth texture instead of depth renderbuffer where possible, uses less video memory but may render slower (or faster) depending on hardware"};
164 cvar_t r_viewfbo = {CVAR_CLIENT | CVAR_SAVE, "r_viewfbo", "0", "enables use of an 8bit (1) or 16bit (2) or 32bit (3) per component float framebuffer render, which may be at a different resolution than the video mode"};
165 cvar_t r_rendertarget_debug = {CVAR_CLIENT, "r_rendertarget_debug", "-1", "replaces the view with the contents of the specified render target (by number - note that these can fluctuate depending on scene)"};
166 cvar_t r_viewscale = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale", "1", "scaling factor for resolution of the fbo rendering method, must be > 0, can be above 1 for a costly antialiasing behavior, typical values are 0.5 for 1/4th as many pixels rendered, or 1 for normal rendering"};
167 cvar_t r_viewscale_fpsscaling = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling", "0", "change resolution based on framerate"};
168 cvar_t r_viewscale_fpsscaling_min = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_min", "0.0625", "worst acceptable quality"};
169 cvar_t r_viewscale_fpsscaling_multiply = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_multiply", "5", "adjust quality up or down by the frametime difference from 1.0/target, multiplied by this factor"};
170 cvar_t r_viewscale_fpsscaling_stepsize = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_stepsize", "0.01", "smallest adjustment to hit the target framerate (this value prevents minute oscillations)"};
171 cvar_t r_viewscale_fpsscaling_stepmax = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_stepmax", "1.00", "largest adjustment to hit the target framerate (this value prevents wild overshooting of the estimate)"};
172 cvar_t r_viewscale_fpsscaling_target = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_target", "70", "desired framerate"};
173
174 cvar_t r_glsl_skeletal = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_skeletal", "1", "render skeletal models faster using a gpu-skinning technique"};
175 cvar_t r_glsl_deluxemapping = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
176 cvar_t r_glsl_offsetmapping = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
177 cvar_t r_glsl_offsetmapping_steps = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_steps", "2", "offset mapping steps (note: too high values may be not supported by your GPU)"};
178 cvar_t r_glsl_offsetmapping_reliefmapping = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
179 cvar_t r_glsl_offsetmapping_reliefmapping_steps = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_steps", "10", "relief mapping steps (note: too high values may be not supported by your GPU)"};
180 cvar_t r_glsl_offsetmapping_reliefmapping_refinesteps = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_refinesteps", "5", "relief mapping refine steps (these are a binary search executed as the last step as given by r_glsl_offsetmapping_reliefmapping_steps)"};
181 cvar_t r_glsl_offsetmapping_scale = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
182 cvar_t r_glsl_offsetmapping_lod = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_lod", "0", "apply distance-based level-of-detail correction to number of offsetmappig steps, effectively making it render faster on large open-area maps"};
183 cvar_t r_glsl_offsetmapping_lod_distance = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_lod_distance", "32", "first LOD level distance, second level (-50% steps) is 2x of this, third (33%) - 3x etc."};
184 cvar_t r_glsl_postprocess = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess", "0", "use a GLSL postprocessing shader"};
185 cvar_t r_glsl_postprocess_uservec1 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec1", "0 0 0 0", "a 4-component vector to pass as uservec1 to the postprocessing shader (only useful if default.glsl has been customized)"};
186 cvar_t r_glsl_postprocess_uservec2 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec2", "0 0 0 0", "a 4-component vector to pass as uservec2 to the postprocessing shader (only useful if default.glsl has been customized)"};
187 cvar_t r_glsl_postprocess_uservec3 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec3", "0 0 0 0", "a 4-component vector to pass as uservec3 to the postprocessing shader (only useful if default.glsl has been customized)"};
188 cvar_t r_glsl_postprocess_uservec4 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec4", "0 0 0 0", "a 4-component vector to pass as uservec4 to the postprocessing shader (only useful if default.glsl has been customized)"};
189 cvar_t r_glsl_postprocess_uservec1_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec1_enable", "1", "enables postprocessing uservec1 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
190 cvar_t r_glsl_postprocess_uservec2_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec2_enable", "1", "enables postprocessing uservec2 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
191 cvar_t r_glsl_postprocess_uservec3_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec3_enable", "1", "enables postprocessing uservec3 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
192 cvar_t r_glsl_postprocess_uservec4_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec4_enable", "1", "enables postprocessing uservec4 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
193 cvar_t r_colorfringe = {CVAR_CLIENT | CVAR_SAVE, "r_colorfringe", "0", "Chromatic aberration. Values higher than 0.025 will noticeably distort the image"};
194
195 cvar_t r_water = {CVAR_CLIENT | CVAR_SAVE, "r_water", "0", "whether to use reflections and refraction on water surfaces (note: r_wateralpha must be set below 1)"};
196 cvar_t r_water_cameraentitiesonly = {CVAR_CLIENT | CVAR_SAVE, "r_water_cameraentitiesonly", "0", "whether to only show QC-defined reflections/refractions (typically used for camera- or portal-like effects)"};
197 cvar_t r_water_clippingplanebias = {CVAR_CLIENT | CVAR_SAVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
198 cvar_t r_water_resolutionmultiplier = {CVAR_CLIENT | CVAR_SAVE, "r_water_resolutionmultiplier", "0.5", "multiplier for screen resolution when rendering refracted/reflected scenes, 1 is full quality, lower values are faster"};
199 cvar_t r_water_refractdistort = {CVAR_CLIENT | CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
200 cvar_t r_water_reflectdistort = {CVAR_CLIENT | CVAR_SAVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
201 cvar_t r_water_scissormode = {CVAR_CLIENT, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
202 cvar_t r_water_lowquality = {CVAR_CLIENT, "r_water_lowquality", "0", "special option to accelerate water rendering: 1 disables all dynamic lights, 2 disables particles too"};
203 cvar_t r_water_hideplayer = {CVAR_CLIENT | CVAR_SAVE, "r_water_hideplayer", "0", "if set to 1 then player will be hidden in refraction views, if set to 2 then player will also be hidden in reflection views, player is always visible in camera views"};
204
205 cvar_t r_lerpsprites = {CVAR_CLIENT | CVAR_SAVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"};
206 cvar_t r_lerpmodels = {CVAR_CLIENT | CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
207 cvar_t r_lerplightstyles = {CVAR_CLIENT | CVAR_SAVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
208 cvar_t r_waterscroll = {CVAR_CLIENT | CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
209
210 cvar_t r_bloom = {CVAR_CLIENT | CVAR_SAVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
211 cvar_t r_bloom_colorscale = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorscale", "1", "how bright the glow is"};
212
213 cvar_t r_bloom_brighten = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_brighten", "2", "how bright the glow is, after subtract/power"};
214 cvar_t r_bloom_blur = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_blur", "4", "how large the glow is"};
215 cvar_t r_bloom_resolution = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
216 cvar_t r_bloom_colorexponent = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorexponent", "1", "how exaggerated the glow is"};
217 cvar_t r_bloom_colorsubtract = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorsubtract", "0.125", "reduces bloom colors by a certain amount"};
218 cvar_t r_bloom_scenebrightness = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_scenebrightness", "1", "global rendering brightness when bloom is enabled"};
219
220 cvar_t r_hdr_scenebrightness = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
221 cvar_t r_hdr_glowintensity = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
222 cvar_t r_hdr_irisadaptation = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation", "0", "adjust scene brightness according to light intensity at player location"};
223 cvar_t r_hdr_irisadaptation_multiplier = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_multiplier", "2", "brightness at which value will be 1.0"};
224 cvar_t r_hdr_irisadaptation_minvalue = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_minvalue", "0.5", "minimum value that can result from multiplier / brightness"};
225 cvar_t r_hdr_irisadaptation_maxvalue = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_maxvalue", "4", "maximum value that can result from multiplier / brightness"};
226 cvar_t r_hdr_irisadaptation_value = {CVAR_CLIENT, "r_hdr_irisadaptation_value", "1", "current value as scenebrightness multiplier, changes continuously when irisadaptation is active"};
227 cvar_t r_hdr_irisadaptation_fade_up = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_fade_up", "0.1", "fade rate at which value adjusts to darkness"};
228 cvar_t r_hdr_irisadaptation_fade_down = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_fade_down", "0.5", "fade rate at which value adjusts to brightness"};
229 cvar_t r_hdr_irisadaptation_radius = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_radius", "15", "lighting within this many units of the eye is averaged"};
230
231 cvar_t r_smoothnormals_areaweighting = {CVAR_CLIENT, "r_smoothnormals_areaweighting", "1", "uses significantly faster (and supposedly higher quality) area-weighted vertex normals and tangent vectors rather than summing normalized triangle normals and tangents"};
232
233 cvar_t developer_texturelogging = {CVAR_CLIENT, "developer_texturelogging", "0", "produces a textures.log file containing names of skins and map textures the engine tried to load"};
234
235 cvar_t gl_lightmaps = {CVAR_CLIENT, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers), a value of 2 keeps normalmap shading"};
236
237 cvar_t r_test = {CVAR_CLIENT, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
238
239 cvar_t r_batch_multidraw = {CVAR_CLIENT | CVAR_SAVE, "r_batch_multidraw", "1", "issue multiple glDrawElements calls when rendering a batch of surfaces with the same texture (otherwise the index data is copied to make it one draw)"};
240 cvar_t r_batch_multidraw_mintriangles = {CVAR_CLIENT | CVAR_SAVE, "r_batch_multidraw_mintriangles", "0", "minimum number of triangles to activate multidraw path (copying small groups of triangles may be faster)"};
241 cvar_t r_batch_debugdynamicvertexpath = {CVAR_CLIENT | CVAR_SAVE, "r_batch_debugdynamicvertexpath", "0", "force the dynamic batching code path for debugging purposes"};
242 cvar_t r_batch_dynamicbuffer = {CVAR_CLIENT | CVAR_SAVE, "r_batch_dynamicbuffer", "0", "use vertex/index buffers for drawing dynamic and copytriangles batches"};
243
244 cvar_t r_glsl_saturation = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
245 cvar_t r_glsl_saturation_redcompensate = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_saturation_redcompensate", "0", "a 'vampire sight' addition to desaturation effect, does compensation for red color, r_glsl_restart is required"};
246
247 cvar_t r_glsl_vertextextureblend_usebothalphas = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_vertextextureblend_usebothalphas", "0", "use both alpha layers on vertex blended surfaces, each alpha layer sets amount of 'blend leak' on another layer, requires mod_q3shader_force_terrain_alphaflag on."};
248
249 cvar_t r_framedatasize = {CVAR_CLIENT | CVAR_SAVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"};
250 cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
251 {
252         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"},
253         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"},
254         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"},
255         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
256 };
257
258 extern cvar_t v_glslgamma_2d;
259
260 extern qboolean v_flipped_state;
261
262 r_framebufferstate_t r_fb;
263
264 /// shadow volume bsp struct with automatically growing nodes buffer
265 svbsp_t r_svbsp;
266
267 int r_uniformbufferalignment = 32; // dynamically updated to match GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
268
269 rtexture_t *r_texture_blanknormalmap;
270 rtexture_t *r_texture_white;
271 rtexture_t *r_texture_grey128;
272 rtexture_t *r_texture_black;
273 rtexture_t *r_texture_notexture;
274 rtexture_t *r_texture_whitecube;
275 rtexture_t *r_texture_normalizationcube;
276 rtexture_t *r_texture_fogattenuation;
277 rtexture_t *r_texture_fogheighttexture;
278 rtexture_t *r_texture_gammaramps;
279 unsigned int r_texture_gammaramps_serial;
280 //rtexture_t *r_texture_fogintensity;
281 rtexture_t *r_texture_reflectcube;
282
283 // TODO: hash lookups?
284 typedef struct cubemapinfo_s
285 {
286         char basename[64];
287         rtexture_t *texture;
288 }
289 cubemapinfo_t;
290
291 int r_texture_numcubemaps;
292 cubemapinfo_t *r_texture_cubemaps[MAX_CUBEMAPS];
293
294 unsigned int r_queries[MAX_OCCLUSION_QUERIES];
295 unsigned int r_numqueries;
296 unsigned int r_maxqueries;
297
298 typedef struct r_qwskincache_s
299 {
300         char name[MAX_QPATH];
301         skinframe_t *skinframe;
302 }
303 r_qwskincache_t;
304
305 static r_qwskincache_t *r_qwskincache;
306 static int r_qwskincache_size;
307
308 /// vertex coordinates for a quad that covers the screen exactly
309 extern const float r_screenvertex3f[12];
310 const float r_screenvertex3f[12] =
311 {
312         0, 0, 0,
313         1, 0, 0,
314         1, 1, 0,
315         0, 1, 0
316 };
317
318 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
319 {
320         int i;
321         for (i = 0;i < verts;i++)
322         {
323                 out[0] = in[0] * r;
324                 out[1] = in[1] * g;
325                 out[2] = in[2] * b;
326                 out[3] = in[3];
327                 in += 4;
328                 out += 4;
329         }
330 }
331
332 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
333 {
334         int i;
335         for (i = 0;i < verts;i++)
336         {
337                 out[0] = r;
338                 out[1] = g;
339                 out[2] = b;
340                 out[3] = a;
341                 out += 4;
342         }
343 }
344
345 // FIXME: move this to client?
346 void FOG_clear(void)
347 {
348         if (gamemode == GAME_NEHAHRA)
349         {
350                 Cvar_Set(&cvars_all, "gl_fogenable", "0");
351                 Cvar_Set(&cvars_all, "gl_fogdensity", "0.2");
352                 Cvar_Set(&cvars_all, "gl_fogred", "0.3");
353                 Cvar_Set(&cvars_all, "gl_foggreen", "0.3");
354                 Cvar_Set(&cvars_all, "gl_fogblue", "0.3");
355         }
356         r_refdef.fog_density = 0;
357         r_refdef.fog_red = 0;
358         r_refdef.fog_green = 0;
359         r_refdef.fog_blue = 0;
360         r_refdef.fog_alpha = 1;
361         r_refdef.fog_start = 0;
362         r_refdef.fog_end = 16384;
363         r_refdef.fog_height = 1<<30;
364         r_refdef.fog_fadedepth = 128;
365         memset(r_refdef.fog_height_texturename, 0, sizeof(r_refdef.fog_height_texturename));
366 }
367
368 static void R_BuildBlankTextures(void)
369 {
370         unsigned char data[4];
371         data[2] = 128; // normal X
372         data[1] = 128; // normal Y
373         data[0] = 255; // normal Z
374         data[3] = 255; // height
375         r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
376         data[0] = 255;
377         data[1] = 255;
378         data[2] = 255;
379         data[3] = 255;
380         r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
381         data[0] = 128;
382         data[1] = 128;
383         data[2] = 128;
384         data[3] = 255;
385         r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
386         data[0] = 0;
387         data[1] = 0;
388         data[2] = 0;
389         data[3] = 255;
390         r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
391 }
392
393 static void R_BuildNoTexture(void)
394 {
395         int x, y;
396         unsigned char pix[16][16][4];
397         // this makes a light grey/dark grey checkerboard texture
398         for (y = 0;y < 16;y++)
399         {
400                 for (x = 0;x < 16;x++)
401                 {
402                         if ((y < 8) ^ (x < 8))
403                         {
404                                 pix[y][x][0] = 128;
405                                 pix[y][x][1] = 128;
406                                 pix[y][x][2] = 128;
407                                 pix[y][x][3] = 255;
408                         }
409                         else
410                         {
411                                 pix[y][x][0] = 64;
412                                 pix[y][x][1] = 64;
413                                 pix[y][x][2] = 64;
414                                 pix[y][x][3] = 255;
415                         }
416                 }
417         }
418         r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, -1, NULL);
419 }
420
421 static void R_BuildWhiteCube(void)
422 {
423         unsigned char data[6*1*1*4];
424         memset(data, 255, sizeof(data));
425         r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
426 }
427
428 static void R_BuildNormalizationCube(void)
429 {
430         int x, y, side;
431         vec3_t v;
432         vec_t s, t, intensity;
433 #define NORMSIZE 64
434         unsigned char *data;
435         data = (unsigned char *)Mem_Alloc(tempmempool, 6*NORMSIZE*NORMSIZE*4);
436         for (side = 0;side < 6;side++)
437         {
438                 for (y = 0;y < NORMSIZE;y++)
439                 {
440                         for (x = 0;x < NORMSIZE;x++)
441                         {
442                                 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
443                                 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
444                                 switch(side)
445                                 {
446                                 default:
447                                 case 0:
448                                         v[0] = 1;
449                                         v[1] = -t;
450                                         v[2] = -s;
451                                         break;
452                                 case 1:
453                                         v[0] = -1;
454                                         v[1] = -t;
455                                         v[2] = s;
456                                         break;
457                                 case 2:
458                                         v[0] = s;
459                                         v[1] = 1;
460                                         v[2] = t;
461                                         break;
462                                 case 3:
463                                         v[0] = s;
464                                         v[1] = -1;
465                                         v[2] = -t;
466                                         break;
467                                 case 4:
468                                         v[0] = s;
469                                         v[1] = -t;
470                                         v[2] = 1;
471                                         break;
472                                 case 5:
473                                         v[0] = -s;
474                                         v[1] = -t;
475                                         v[2] = -1;
476                                         break;
477                                 }
478                                 intensity = 127.0f / sqrt(DotProduct(v, v));
479                                 data[((side*64+y)*64+x)*4+2] = (unsigned char)(128.0f + intensity * v[0]);
480                                 data[((side*64+y)*64+x)*4+1] = (unsigned char)(128.0f + intensity * v[1]);
481                                 data[((side*64+y)*64+x)*4+0] = (unsigned char)(128.0f + intensity * v[2]);
482                                 data[((side*64+y)*64+x)*4+3] = 255;
483                         }
484                 }
485         }
486         r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
487         Mem_Free(data);
488 }
489
490 static void R_BuildFogTexture(void)
491 {
492         int x, b;
493 #define FOGWIDTH 256
494         unsigned char data1[FOGWIDTH][4];
495         //unsigned char data2[FOGWIDTH][4];
496         double d, r, alpha;
497
498         r_refdef.fogmasktable_start = r_refdef.fog_start;
499         r_refdef.fogmasktable_alpha = r_refdef.fog_alpha;
500         r_refdef.fogmasktable_range = r_refdef.fogrange;
501         r_refdef.fogmasktable_density = r_refdef.fog_density;
502
503         r = r_refdef.fogmasktable_range / FOGMASKTABLEWIDTH;
504         for (x = 0;x < FOGMASKTABLEWIDTH;x++)
505         {
506                 d = (x * r - r_refdef.fogmasktable_start);
507                 if(developer_extra.integer)
508                         Con_DPrintf("%f ", d);
509                 d = max(0, d);
510                 if (r_fog_exp2.integer)
511                         alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d);
512                 else
513                         alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d);
514                 if(developer_extra.integer)
515                         Con_DPrintf(" : %f ", alpha);
516                 alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha;
517                 if(developer_extra.integer)
518                         Con_DPrintf(" = %f\n", alpha);
519                 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
520         }
521
522         for (x = 0;x < FOGWIDTH;x++)
523         {
524                 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
525                 data1[x][0] = b;
526                 data1[x][1] = b;
527                 data1[x][2] = b;
528                 data1[x][3] = 255;
529                 //data2[x][0] = 255 - b;
530                 //data2[x][1] = 255 - b;
531                 //data2[x][2] = 255 - b;
532                 //data2[x][3] = 255;
533         }
534         if (r_texture_fogattenuation)
535         {
536                 R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
537                 //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
538         }
539         else
540         {
541                 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
542                 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
543         }
544 }
545
546 static void R_BuildFogHeightTexture(void)
547 {
548         unsigned char *inpixels;
549         int size;
550         int x;
551         int y;
552         int j;
553         float c[4];
554         float f;
555         inpixels = NULL;
556         strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename));
557         if (r_refdef.fogheighttexturename[0])
558                 inpixels = loadimagepixelsbgra(r_refdef.fogheighttexturename, true, false, false, NULL);
559         if (!inpixels)
560         {
561                 r_refdef.fog_height_tablesize = 0;
562                 if (r_texture_fogheighttexture)
563                         R_FreeTexture(r_texture_fogheighttexture);
564                 r_texture_fogheighttexture = NULL;
565                 if (r_refdef.fog_height_table2d)
566                         Mem_Free(r_refdef.fog_height_table2d);
567                 r_refdef.fog_height_table2d = NULL;
568                 if (r_refdef.fog_height_table1d)
569                         Mem_Free(r_refdef.fog_height_table1d);
570                 r_refdef.fog_height_table1d = NULL;
571                 return;
572         }
573         size = image_width;
574         r_refdef.fog_height_tablesize = size;
575         r_refdef.fog_height_table1d = (unsigned char *)Mem_Alloc(r_main_mempool, size * 4);
576         r_refdef.fog_height_table2d = (unsigned char *)Mem_Alloc(r_main_mempool, size * size * 4);
577         memcpy(r_refdef.fog_height_table1d, inpixels, size * 4);
578         Mem_Free(inpixels);
579         // LadyHavoc: now the magic - what is that table2d for?  it is a cooked
580         // average fog color table accounting for every fog layer between a point
581         // and the camera.  (Note: attenuation is handled separately!)
582         for (y = 0;y < size;y++)
583         {
584                 for (x = 0;x < size;x++)
585                 {
586                         Vector4Clear(c);
587                         f = 0;
588                         if (x < y)
589                         {
590                                 for (j = x;j <= y;j++)
591                                 {
592                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
593                                         f++;
594                                 }
595                         }
596                         else
597                         {
598                                 for (j = x;j >= y;j--)
599                                 {
600                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
601                                         f++;
602                                 }
603                         }
604                         f = 1.0f / f;
605                         r_refdef.fog_height_table2d[(y*size+x)*4+0] = (unsigned char)(c[0] * f);
606                         r_refdef.fog_height_table2d[(y*size+x)*4+1] = (unsigned char)(c[1] * f);
607                         r_refdef.fog_height_table2d[(y*size+x)*4+2] = (unsigned char)(c[2] * f);
608                         r_refdef.fog_height_table2d[(y*size+x)*4+3] = (unsigned char)(c[3] * f);
609                 }
610         }
611         r_texture_fogheighttexture = R_LoadTexture2D(r_main_texturepool, "fogheighttable", size, size, r_refdef.fog_height_table2d, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_CLAMP, -1, NULL);
612 }
613
614 //=======================================================================================================================================================
615
616 static const char *builtinshaderstrings[] =
617 {
618 #include "shader_glsl.h"
619 0
620 };
621
622 //=======================================================================================================================================================
623
624 typedef struct shaderpermutationinfo_s
625 {
626         const char *pretext;
627         const char *name;
628 }
629 shaderpermutationinfo_t;
630
631 typedef struct shadermodeinfo_s
632 {
633         const char *sourcebasename;
634         const char *extension;
635         const char **builtinshaderstrings;
636         const char *pretext;
637         const char *name;
638         char *filename;
639         char *builtinstring;
640         int builtincrc;
641 }
642 shadermodeinfo_t;
643
644 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
645 shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
646 {
647         {"#define USEDIFFUSE\n", " diffuse"},
648         {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
649         {"#define USEVIEWTINT\n", " viewtint"},
650         {"#define USECOLORMAPPING\n", " colormapping"},
651         {"#define USESATURATION\n", " saturation"},
652         {"#define USEFOGINSIDE\n", " foginside"},
653         {"#define USEFOGOUTSIDE\n", " fogoutside"},
654         {"#define USEFOGHEIGHTTEXTURE\n", " fogheighttexture"},
655         {"#define USEFOGALPHAHACK\n", " fogalphahack"},
656         {"#define USEGAMMARAMPS\n", " gammaramps"},
657         {"#define USECUBEFILTER\n", " cubefilter"},
658         {"#define USEGLOW\n", " glow"},
659         {"#define USEBLOOM\n", " bloom"},
660         {"#define USESPECULAR\n", " specular"},
661         {"#define USEPOSTPROCESSING\n", " postprocessing"},
662         {"#define USEREFLECTION\n", " reflection"},
663         {"#define USEOFFSETMAPPING\n", " offsetmapping"},
664         {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
665         {"#define USESHADOWMAP2D\n", " shadowmap2d"},
666         {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm
667         {"#define USESHADOWMAPORTHO\n", " shadowmaportho"},
668         {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
669         {"#define USEALPHAKILL\n", " alphakill"},
670         {"#define USEREFLECTCUBE\n", " reflectcube"},
671         {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"},
672         {"#define USEBOUNCEGRID\n", " bouncegrid"},
673         {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm
674         {"#define USETRIPPY\n", " trippy"},
675         {"#define USEDEPTHRGB\n", " depthrgb"},
676         {"#define USEALPHAGENVERTEX\n", " alphagenvertex"},
677         {"#define USESKELETAL\n", " skeletal"},
678         {"#define USEOCCLUDE\n", " occlude"}
679 };
680
681 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
682 shadermodeinfo_t shadermodeinfo[SHADERLANGUAGE_COUNT][SHADERMODE_COUNT] =
683 {
684         // SHADERLANGUAGE_GLSL
685         {
686                 {"combined", "glsl", builtinshaderstrings, "#define MODE_GENERIC\n", " generic"},
687                 {"combined", "glsl", builtinshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
688                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
689                 {"combined", "glsl", builtinshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
690                 {"combined", "glsl", builtinshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
691                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
692                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
693                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
694                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
695                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
696                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
697                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
698                 {"combined", "glsl", builtinshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
699                 {"combined", "glsl", builtinshaderstrings, "#define MODE_WATER\n", " water"},
700                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
701                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
702         },
703 };
704
705 struct r_glsl_permutation_s;
706 typedef struct r_glsl_permutation_s
707 {
708         /// hash lookup data
709         struct r_glsl_permutation_s *hashnext;
710         unsigned int mode;
711         dpuint64 permutation;
712
713         /// indicates if we have tried compiling this permutation already
714         qboolean compiled;
715         /// 0 if compilation failed
716         int program;
717         // texture units assigned to each detected uniform
718         int tex_Texture_First;
719         int tex_Texture_Second;
720         int tex_Texture_GammaRamps;
721         int tex_Texture_Normal;
722         int tex_Texture_Color;
723         int tex_Texture_Gloss;
724         int tex_Texture_Glow;
725         int tex_Texture_SecondaryNormal;
726         int tex_Texture_SecondaryColor;
727         int tex_Texture_SecondaryGloss;
728         int tex_Texture_SecondaryGlow;
729         int tex_Texture_Pants;
730         int tex_Texture_Shirt;
731         int tex_Texture_FogHeightTexture;
732         int tex_Texture_FogMask;
733         int tex_Texture_Lightmap;
734         int tex_Texture_Deluxemap;
735         int tex_Texture_Attenuation;
736         int tex_Texture_Cube;
737         int tex_Texture_Refraction;
738         int tex_Texture_Reflection;
739         int tex_Texture_ShadowMap2D;
740         int tex_Texture_CubeProjection;
741         int tex_Texture_ScreenNormalMap;
742         int tex_Texture_ScreenDiffuse;
743         int tex_Texture_ScreenSpecular;
744         int tex_Texture_ReflectMask;
745         int tex_Texture_ReflectCube;
746         int tex_Texture_BounceGrid;
747         /// locations of detected uniforms in program object, or -1 if not found
748         int loc_Texture_First;
749         int loc_Texture_Second;
750         int loc_Texture_GammaRamps;
751         int loc_Texture_Normal;
752         int loc_Texture_Color;
753         int loc_Texture_Gloss;
754         int loc_Texture_Glow;
755         int loc_Texture_SecondaryNormal;
756         int loc_Texture_SecondaryColor;
757         int loc_Texture_SecondaryGloss;
758         int loc_Texture_SecondaryGlow;
759         int loc_Texture_Pants;
760         int loc_Texture_Shirt;
761         int loc_Texture_FogHeightTexture;
762         int loc_Texture_FogMask;
763         int loc_Texture_Lightmap;
764         int loc_Texture_Deluxemap;
765         int loc_Texture_Attenuation;
766         int loc_Texture_Cube;
767         int loc_Texture_Refraction;
768         int loc_Texture_Reflection;
769         int loc_Texture_ShadowMap2D;
770         int loc_Texture_CubeProjection;
771         int loc_Texture_ScreenNormalMap;
772         int loc_Texture_ScreenDiffuse;
773         int loc_Texture_ScreenSpecular;
774         int loc_Texture_ReflectMask;
775         int loc_Texture_ReflectCube;
776         int loc_Texture_BounceGrid;
777         int loc_Alpha;
778         int loc_BloomBlur_Parameters;
779         int loc_ClientTime;
780         int loc_Color_Ambient;
781         int loc_Color_Diffuse;
782         int loc_Color_Specular;
783         int loc_Color_Glow;
784         int loc_Color_Pants;
785         int loc_Color_Shirt;
786         int loc_DeferredColor_Ambient;
787         int loc_DeferredColor_Diffuse;
788         int loc_DeferredColor_Specular;
789         int loc_DeferredMod_Diffuse;
790         int loc_DeferredMod_Specular;
791         int loc_DistortScaleRefractReflect;
792         int loc_EyePosition;
793         int loc_FogColor;
794         int loc_FogHeightFade;
795         int loc_FogPlane;
796         int loc_FogPlaneViewDist;
797         int loc_FogRangeRecip;
798         int loc_LightColor;
799         int loc_LightDir;
800         int loc_LightPosition;
801         int loc_OffsetMapping_ScaleSteps;
802         int loc_OffsetMapping_LodDistance;
803         int loc_OffsetMapping_Bias;
804         int loc_PixelSize;
805         int loc_ReflectColor;
806         int loc_ReflectFactor;
807         int loc_ReflectOffset;
808         int loc_RefractColor;
809         int loc_Saturation;
810         int loc_ScreenCenterRefractReflect;
811         int loc_ScreenScaleRefractReflect;
812         int loc_ScreenToDepth;
813         int loc_ShadowMap_Parameters;
814         int loc_ShadowMap_TextureScale;
815         int loc_SpecularPower;
816         int loc_Skeletal_Transform12;
817         int loc_UserVec1;
818         int loc_UserVec2;
819         int loc_UserVec3;
820         int loc_UserVec4;
821         int loc_ColorFringe;
822         int loc_ViewTintColor;
823         int loc_ViewToLight;
824         int loc_ModelToLight;
825         int loc_TexMatrix;
826         int loc_BackgroundTexMatrix;
827         int loc_ModelViewProjectionMatrix;
828         int loc_ModelViewMatrix;
829         int loc_PixelToScreenTexCoord;
830         int loc_ModelToReflectCube;
831         int loc_ShadowMapMatrix;
832         int loc_BloomColorSubtract;
833         int loc_NormalmapScrollBlend;
834         int loc_BounceGridMatrix;
835         int loc_BounceGridIntensity;
836         /// uniform block bindings
837         int ubibind_Skeletal_Transform12_UniformBlock;
838         /// uniform block indices
839         int ubiloc_Skeletal_Transform12_UniformBlock;
840 }
841 r_glsl_permutation_t;
842
843 #define SHADERPERMUTATION_HASHSIZE 256
844
845
846 // non-degradable "lightweight" shader parameters to keep the permutations simpler
847 // these can NOT degrade! only use for simple stuff
848 enum
849 {
850         SHADERSTATICPARM_SATURATION_REDCOMPENSATE = 0, ///< red compensation filter for saturation
851         SHADERSTATICPARM_EXACTSPECULARMATH = 1, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
852         SHADERSTATICPARM_POSTPROCESS_USERVEC1 = 2, ///< postprocess uservec1 is enabled
853         SHADERSTATICPARM_POSTPROCESS_USERVEC2 = 3, ///< postprocess uservec2 is enabled
854         SHADERSTATICPARM_POSTPROCESS_USERVEC3 = 4, ///< postprocess uservec3 is enabled
855         SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5,  ///< postprocess uservec4 is enabled
856         SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending
857         SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7,  ///< LOD for offsetmapping
858         SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1
859         SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2
860         SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
861         SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
862         SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
863         SHADERSTATICPARM_FXAA = 13 ///< fast approximate anti aliasing
864 };
865 #define SHADERSTATICPARMS_COUNT 14
866
867 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
868 static int shaderstaticparms_count = 0;
869
870 static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0};
871 #define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F))
872
873 extern qboolean r_shadow_shadowmapsampler;
874 extern int r_shadow_shadowmappcf;
875 qboolean R_CompileShader_CheckStaticParms(void)
876 {
877         static int r_compileshader_staticparms_save[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5];
878         memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
879         memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
880
881         // detect all
882         if (r_glsl_saturation_redcompensate.integer)
883                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SATURATION_REDCOMPENSATE);
884         if (r_glsl_vertextextureblend_usebothalphas.integer)
885                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS);
886         if (r_shadow_glossexact.integer)
887                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_EXACTSPECULARMATH);
888         if (r_glsl_postprocess.integer)
889         {
890                 if (r_glsl_postprocess_uservec1_enable.integer)
891                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC1);
892                 if (r_glsl_postprocess_uservec2_enable.integer)
893                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC2);
894                 if (r_glsl_postprocess_uservec3_enable.integer)
895                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC3);
896                 if (r_glsl_postprocess_uservec4_enable.integer)
897                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
898         }
899         if (r_fxaa.integer)
900                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_FXAA);
901         if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
902                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
903
904         if (r_shadow_shadowmapsampler)
905                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER);
906         if (r_shadow_shadowmappcf > 1)
907                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2);
908         else if (r_shadow_shadowmappcf)
909                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1);
910         if (r_celshading.integer)
911                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING);
912         if (r_celoutlines.integer)
913                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES);
914
915         return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
916 }
917
918 #define R_COMPILESHADER_STATICPARM_EMIT(p, n) \
919         if(r_compileshader_staticparms[(p) >> 5] & (1 << ((p) & 0x1F))) \
920                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \
921         else \
922                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n"
923 static void R_CompileShader_AddStaticParms(unsigned int mode, dpuint64 permutation)
924 {
925         shaderstaticparms_count = 0;
926
927         // emit all
928         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SATURATION_REDCOMPENSATE, "SATURATION_REDCOMPENSATE");
929         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_EXACTSPECULARMATH, "USEEXACTSPECULARMATH");
930         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC1, "USERVEC1");
931         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC2, "USERVEC2");
932         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC3, "USERVEC3");
933         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4");
934         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS");
935         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD");
936         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1");
937         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2");
938         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
939         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
940         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
941         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
942 }
943
944 /// information about each possible shader permutation
945 r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
946 /// currently selected permutation
947 r_glsl_permutation_t *r_glsl_permutation;
948 /// storage for permutations linked in the hash table
949 memexpandablearray_t r_glsl_permutationarray;
950
951 static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, dpuint64 permutation)
952 {
953         //unsigned int hashdepth = 0;
954         unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
955         r_glsl_permutation_t *p;
956         for (p = r_glsl_permutationhash[mode][hashindex];p;p = p->hashnext)
957         {
958                 if (p->mode == mode && p->permutation == permutation)
959                 {
960                         //if (hashdepth > 10)
961                         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
962                         return p;
963                 }
964                 //hashdepth++;
965         }
966         p = (r_glsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_glsl_permutationarray);
967         p->mode = mode;
968         p->permutation = permutation;
969         p->hashnext = r_glsl_permutationhash[mode][hashindex];
970         r_glsl_permutationhash[mode][hashindex] = p;
971         //if (hashdepth > 10)
972         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
973         return p;
974 }
975
976 static char *R_ShaderStrCat(const char **strings)
977 {
978         char *string, *s;
979         const char **p = strings;
980         const char *t;
981         size_t len = 0;
982         for (p = strings;(t = *p);p++)
983                 len += strlen(t);
984         len++;
985         s = string = (char *)Mem_Alloc(r_main_mempool, len);
986         len = 0;
987         for (p = strings;(t = *p);p++)
988         {
989                 len = strlen(t);
990                 memcpy(s, t, len);
991                 s += len;
992         }
993         *s = 0;
994         return string;
995 }
996
997 static char *R_ShaderStrCat(const char **strings);
998 static void R_InitShaderModeInfo(void)
999 {
1000         int i, language;
1001         shadermodeinfo_t *modeinfo;
1002         // we have a bunch of things to compute that weren't calculated at engine compile time - all filenames should have a crc of the builtin strings to prevent accidental overrides (any customization must be updated to match engine)
1003         for (language = 0; language < SHADERLANGUAGE_COUNT; language++)
1004         {
1005                 for (i = 0; i < SHADERMODE_COUNT; i++)
1006                 {
1007                         char filename[MAX_QPATH];
1008                         modeinfo = &shadermodeinfo[language][i];
1009                         modeinfo->builtinstring = R_ShaderStrCat(modeinfo->builtinshaderstrings);
1010                         modeinfo->builtincrc = CRC_Block((const unsigned char *)modeinfo->builtinstring, strlen(modeinfo->builtinstring));
1011                         dpsnprintf(filename, sizeof(filename), "%s/%s_crc%i.%s", modeinfo->extension, modeinfo->sourcebasename, modeinfo->builtincrc, modeinfo->extension);
1012                         modeinfo->filename = Mem_strdup(r_main_mempool, filename);
1013                 }
1014         }
1015 }
1016
1017 static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qboolean printfromdisknotice, qboolean builtinonly)
1018 {
1019         char *shaderstring;
1020         // if the mode has no filename we have to return the builtin string
1021         if (builtinonly || !modeinfo->filename)
1022                 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1023         // note that FS_LoadFile appends a 0 byte to make it a valid string
1024         shaderstring = (char *)FS_LoadFile(modeinfo->filename, r_main_mempool, false, NULL);
1025         if (shaderstring)
1026         {
1027                 if (printfromdisknotice)
1028                         Con_DPrintf("Loading shaders from file %s...\n", modeinfo->filename);
1029                 return shaderstring;
1030         }
1031         // fall back to builtinstring
1032         return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1033 }
1034
1035 static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, dpuint64 permutation)
1036 {
1037         int i;
1038         int ubibind;
1039         int sampler;
1040         shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode];
1041         char *sourcestring;
1042         char permutationname[256];
1043         int vertstrings_count = 0;
1044         int geomstrings_count = 0;
1045         int fragstrings_count = 0;
1046         const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1047         const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1048         const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1049
1050         if (p->compiled)
1051                 return;
1052         p->compiled = true;
1053         p->program = 0;
1054
1055         permutationname[0] = 0;
1056         sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false);
1057
1058         strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
1059
1060         // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object)
1061         if(vid.support.glshaderversion >= 140)
1062         {
1063                 vertstrings_list[vertstrings_count++] = "#version 140\n";
1064                 geomstrings_list[geomstrings_count++] = "#version 140\n";
1065                 fragstrings_list[fragstrings_count++] = "#version 140\n";
1066                 vertstrings_list[vertstrings_count++] = "#define GLSL140\n";
1067                 geomstrings_list[geomstrings_count++] = "#define GLSL140\n";
1068                 fragstrings_list[fragstrings_count++] = "#define GLSL140\n";
1069         }
1070         // if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad)
1071         else if(vid.support.glshaderversion >= 130)
1072         {
1073                 vertstrings_list[vertstrings_count++] = "#version 130\n";
1074                 geomstrings_list[geomstrings_count++] = "#version 130\n";
1075                 fragstrings_list[fragstrings_count++] = "#version 130\n";
1076                 vertstrings_list[vertstrings_count++] = "#define GLSL130\n";
1077                 geomstrings_list[geomstrings_count++] = "#define GLSL130\n";
1078                 fragstrings_list[fragstrings_count++] = "#define GLSL130\n";
1079         }
1080         // if we can do #version 120, we should (this adds the invariant keyword)
1081         else if(vid.support.glshaderversion >= 120)
1082         {
1083                 vertstrings_list[vertstrings_count++] = "#version 120\n";
1084                 geomstrings_list[geomstrings_count++] = "#version 120\n";
1085                 fragstrings_list[fragstrings_count++] = "#version 120\n";
1086                 vertstrings_list[vertstrings_count++] = "#define GLSL120\n";
1087                 geomstrings_list[geomstrings_count++] = "#define GLSL120\n";
1088                 fragstrings_list[fragstrings_count++] = "#define GLSL120\n";
1089         }
1090         // GLES also adds several things from GLSL120
1091         switch(vid.renderpath)
1092         {
1093         case RENDERPATH_GLES2:
1094                 vertstrings_list[vertstrings_count++] = "#define GLES\n";
1095                 geomstrings_list[geomstrings_count++] = "#define GLES\n";
1096                 fragstrings_list[fragstrings_count++] = "#define GLES\n";
1097                 break;
1098         default:
1099                 break;
1100         }
1101
1102         // the first pretext is which type of shader to compile as
1103         // (later these will all be bound together as a program object)
1104         vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
1105         geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
1106         fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
1107
1108         // the second pretext is the mode (for example a light source)
1109         vertstrings_list[vertstrings_count++] = modeinfo->pretext;
1110         geomstrings_list[geomstrings_count++] = modeinfo->pretext;
1111         fragstrings_list[fragstrings_count++] = modeinfo->pretext;
1112         strlcat(permutationname, modeinfo->name, sizeof(permutationname));
1113
1114         // now add all the permutation pretexts
1115         for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1116         {
1117                 if (permutation & (1ll<<i))
1118                 {
1119                         vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
1120                         geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
1121                         fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
1122                         strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
1123                 }
1124                 else
1125                 {
1126                         // keep line numbers correct
1127                         vertstrings_list[vertstrings_count++] = "\n";
1128                         geomstrings_list[geomstrings_count++] = "\n";
1129                         fragstrings_list[fragstrings_count++] = "\n";
1130                 }
1131         }
1132
1133         // add static parms
1134         R_CompileShader_AddStaticParms(mode, permutation);
1135         memcpy((char *)(vertstrings_list + vertstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1136         vertstrings_count += shaderstaticparms_count;
1137         memcpy((char *)(geomstrings_list + geomstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1138         geomstrings_count += shaderstaticparms_count;
1139         memcpy((char *)(fragstrings_list + fragstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1140         fragstrings_count += shaderstaticparms_count;
1141
1142         // now append the shader text itself
1143         vertstrings_list[vertstrings_count++] = sourcestring;
1144         geomstrings_list[geomstrings_count++] = sourcestring;
1145         fragstrings_list[fragstrings_count++] = sourcestring;
1146
1147         // we don't currently use geometry shaders for anything, so just empty the list
1148         geomstrings_count = 0;
1149
1150         // compile the shader program
1151         if (vertstrings_count + geomstrings_count + fragstrings_count)
1152                 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1153         if (p->program)
1154         {
1155                 CHECKGLERROR
1156                 qglUseProgram(p->program);CHECKGLERROR
1157                 // look up all the uniform variable names we care about, so we don't
1158                 // have to look them up every time we set them
1159
1160 #if 0
1161                 // debugging aid
1162                 {
1163                         GLint activeuniformindex = 0;
1164                         GLint numactiveuniforms = 0;
1165                         char uniformname[128];
1166                         GLsizei uniformnamelength = 0;
1167                         GLint uniformsize = 0;
1168                         GLenum uniformtype = 0;
1169                         memset(uniformname, 0, sizeof(uniformname));
1170                         qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms);
1171                         Con_Printf("Shader has %i uniforms\n", numactiveuniforms);
1172                         for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++)
1173                         {
1174                                 qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname);
1175                                 Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype);
1176                         }
1177                 }
1178 #endif
1179
1180                 p->loc_Texture_First              = qglGetUniformLocation(p->program, "Texture_First");
1181                 p->loc_Texture_Second             = qglGetUniformLocation(p->program, "Texture_Second");
1182                 p->loc_Texture_GammaRamps         = qglGetUniformLocation(p->program, "Texture_GammaRamps");
1183                 p->loc_Texture_Normal             = qglGetUniformLocation(p->program, "Texture_Normal");
1184                 p->loc_Texture_Color              = qglGetUniformLocation(p->program, "Texture_Color");
1185                 p->loc_Texture_Gloss              = qglGetUniformLocation(p->program, "Texture_Gloss");
1186                 p->loc_Texture_Glow               = qglGetUniformLocation(p->program, "Texture_Glow");
1187                 p->loc_Texture_SecondaryNormal    = qglGetUniformLocation(p->program, "Texture_SecondaryNormal");
1188                 p->loc_Texture_SecondaryColor     = qglGetUniformLocation(p->program, "Texture_SecondaryColor");
1189                 p->loc_Texture_SecondaryGloss     = qglGetUniformLocation(p->program, "Texture_SecondaryGloss");
1190                 p->loc_Texture_SecondaryGlow      = qglGetUniformLocation(p->program, "Texture_SecondaryGlow");
1191                 p->loc_Texture_Pants              = qglGetUniformLocation(p->program, "Texture_Pants");
1192                 p->loc_Texture_Shirt              = qglGetUniformLocation(p->program, "Texture_Shirt");
1193                 p->loc_Texture_FogHeightTexture   = qglGetUniformLocation(p->program, "Texture_FogHeightTexture");
1194                 p->loc_Texture_FogMask            = qglGetUniformLocation(p->program, "Texture_FogMask");
1195                 p->loc_Texture_Lightmap           = qglGetUniformLocation(p->program, "Texture_Lightmap");
1196                 p->loc_Texture_Deluxemap          = qglGetUniformLocation(p->program, "Texture_Deluxemap");
1197                 p->loc_Texture_Attenuation        = qglGetUniformLocation(p->program, "Texture_Attenuation");
1198                 p->loc_Texture_Cube               = qglGetUniformLocation(p->program, "Texture_Cube");
1199                 p->loc_Texture_Refraction         = qglGetUniformLocation(p->program, "Texture_Refraction");
1200                 p->loc_Texture_Reflection         = qglGetUniformLocation(p->program, "Texture_Reflection");
1201                 p->loc_Texture_ShadowMap2D        = qglGetUniformLocation(p->program, "Texture_ShadowMap2D");
1202                 p->loc_Texture_CubeProjection     = qglGetUniformLocation(p->program, "Texture_CubeProjection");
1203                 p->loc_Texture_ScreenNormalMap    = qglGetUniformLocation(p->program, "Texture_ScreenNormalMap");
1204                 p->loc_Texture_ScreenDiffuse      = qglGetUniformLocation(p->program, "Texture_ScreenDiffuse");
1205                 p->loc_Texture_ScreenSpecular     = qglGetUniformLocation(p->program, "Texture_ScreenSpecular");
1206                 p->loc_Texture_ReflectMask        = qglGetUniformLocation(p->program, "Texture_ReflectMask");
1207                 p->loc_Texture_ReflectCube        = qglGetUniformLocation(p->program, "Texture_ReflectCube");
1208                 p->loc_Texture_BounceGrid         = qglGetUniformLocation(p->program, "Texture_BounceGrid");
1209                 p->loc_Alpha                      = qglGetUniformLocation(p->program, "Alpha");
1210                 p->loc_BloomBlur_Parameters       = qglGetUniformLocation(p->program, "BloomBlur_Parameters");
1211                 p->loc_ClientTime                 = qglGetUniformLocation(p->program, "ClientTime");
1212                 p->loc_Color_Ambient              = qglGetUniformLocation(p->program, "Color_Ambient");
1213                 p->loc_Color_Diffuse              = qglGetUniformLocation(p->program, "Color_Diffuse");
1214                 p->loc_Color_Specular             = qglGetUniformLocation(p->program, "Color_Specular");
1215                 p->loc_Color_Glow                 = qglGetUniformLocation(p->program, "Color_Glow");
1216                 p->loc_Color_Pants                = qglGetUniformLocation(p->program, "Color_Pants");
1217                 p->loc_Color_Shirt                = qglGetUniformLocation(p->program, "Color_Shirt");
1218                 p->loc_DeferredColor_Ambient      = qglGetUniformLocation(p->program, "DeferredColor_Ambient");
1219                 p->loc_DeferredColor_Diffuse      = qglGetUniformLocation(p->program, "DeferredColor_Diffuse");
1220                 p->loc_DeferredColor_Specular     = qglGetUniformLocation(p->program, "DeferredColor_Specular");
1221                 p->loc_DeferredMod_Diffuse        = qglGetUniformLocation(p->program, "DeferredMod_Diffuse");
1222                 p->loc_DeferredMod_Specular       = qglGetUniformLocation(p->program, "DeferredMod_Specular");
1223                 p->loc_DistortScaleRefractReflect = qglGetUniformLocation(p->program, "DistortScaleRefractReflect");
1224                 p->loc_EyePosition                = qglGetUniformLocation(p->program, "EyePosition");
1225                 p->loc_FogColor                   = qglGetUniformLocation(p->program, "FogColor");
1226                 p->loc_FogHeightFade              = qglGetUniformLocation(p->program, "FogHeightFade");
1227                 p->loc_FogPlane                   = qglGetUniformLocation(p->program, "FogPlane");
1228                 p->loc_FogPlaneViewDist           = qglGetUniformLocation(p->program, "FogPlaneViewDist");
1229                 p->loc_FogRangeRecip              = qglGetUniformLocation(p->program, "FogRangeRecip");
1230                 p->loc_LightColor                 = qglGetUniformLocation(p->program, "LightColor");
1231                 p->loc_LightDir                   = qglGetUniformLocation(p->program, "LightDir");
1232                 p->loc_LightPosition              = qglGetUniformLocation(p->program, "LightPosition");
1233                 p->loc_OffsetMapping_ScaleSteps   = qglGetUniformLocation(p->program, "OffsetMapping_ScaleSteps");
1234                 p->loc_OffsetMapping_LodDistance  = qglGetUniformLocation(p->program, "OffsetMapping_LodDistance");
1235                 p->loc_OffsetMapping_Bias         = qglGetUniformLocation(p->program, "OffsetMapping_Bias");
1236                 p->loc_PixelSize                  = qglGetUniformLocation(p->program, "PixelSize");
1237                 p->loc_ReflectColor               = qglGetUniformLocation(p->program, "ReflectColor");
1238                 p->loc_ReflectFactor              = qglGetUniformLocation(p->program, "ReflectFactor");
1239                 p->loc_ReflectOffset              = qglGetUniformLocation(p->program, "ReflectOffset");
1240                 p->loc_RefractColor               = qglGetUniformLocation(p->program, "RefractColor");
1241                 p->loc_Saturation                 = qglGetUniformLocation(p->program, "Saturation");
1242                 p->loc_ScreenCenterRefractReflect = qglGetUniformLocation(p->program, "ScreenCenterRefractReflect");
1243                 p->loc_ScreenScaleRefractReflect  = qglGetUniformLocation(p->program, "ScreenScaleRefractReflect");
1244                 p->loc_ScreenToDepth              = qglGetUniformLocation(p->program, "ScreenToDepth");
1245                 p->loc_ShadowMap_Parameters       = qglGetUniformLocation(p->program, "ShadowMap_Parameters");
1246                 p->loc_ShadowMap_TextureScale     = qglGetUniformLocation(p->program, "ShadowMap_TextureScale");
1247                 p->loc_SpecularPower              = qglGetUniformLocation(p->program, "SpecularPower");
1248                 p->loc_UserVec1                   = qglGetUniformLocation(p->program, "UserVec1");
1249                 p->loc_UserVec2                   = qglGetUniformLocation(p->program, "UserVec2");
1250                 p->loc_UserVec3                   = qglGetUniformLocation(p->program, "UserVec3");
1251                 p->loc_UserVec4                   = qglGetUniformLocation(p->program, "UserVec4");
1252                 p->loc_ColorFringe                = qglGetUniformLocation(p->program, "ColorFringe");
1253                 p->loc_ViewTintColor              = qglGetUniformLocation(p->program, "ViewTintColor");
1254                 p->loc_ViewToLight                = qglGetUniformLocation(p->program, "ViewToLight");
1255                 p->loc_ModelToLight               = qglGetUniformLocation(p->program, "ModelToLight");
1256                 p->loc_TexMatrix                  = qglGetUniformLocation(p->program, "TexMatrix");
1257                 p->loc_BackgroundTexMatrix        = qglGetUniformLocation(p->program, "BackgroundTexMatrix");
1258                 p->loc_ModelViewMatrix            = qglGetUniformLocation(p->program, "ModelViewMatrix");
1259                 p->loc_ModelViewProjectionMatrix  = qglGetUniformLocation(p->program, "ModelViewProjectionMatrix");
1260                 p->loc_PixelToScreenTexCoord      = qglGetUniformLocation(p->program, "PixelToScreenTexCoord");
1261                 p->loc_ModelToReflectCube         = qglGetUniformLocation(p->program, "ModelToReflectCube");
1262                 p->loc_ShadowMapMatrix            = qglGetUniformLocation(p->program, "ShadowMapMatrix");
1263                 p->loc_BloomColorSubtract         = qglGetUniformLocation(p->program, "BloomColorSubtract");
1264                 p->loc_NormalmapScrollBlend       = qglGetUniformLocation(p->program, "NormalmapScrollBlend");
1265                 p->loc_BounceGridMatrix           = qglGetUniformLocation(p->program, "BounceGridMatrix");
1266                 p->loc_BounceGridIntensity        = qglGetUniformLocation(p->program, "BounceGridIntensity");
1267                 // initialize the samplers to refer to the texture units we use
1268                 p->tex_Texture_First = -1;
1269                 p->tex_Texture_Second = -1;
1270                 p->tex_Texture_GammaRamps = -1;
1271                 p->tex_Texture_Normal = -1;
1272                 p->tex_Texture_Color = -1;
1273                 p->tex_Texture_Gloss = -1;
1274                 p->tex_Texture_Glow = -1;
1275                 p->tex_Texture_SecondaryNormal = -1;
1276                 p->tex_Texture_SecondaryColor = -1;
1277                 p->tex_Texture_SecondaryGloss = -1;
1278                 p->tex_Texture_SecondaryGlow = -1;
1279                 p->tex_Texture_Pants = -1;
1280                 p->tex_Texture_Shirt = -1;
1281                 p->tex_Texture_FogHeightTexture = -1;
1282                 p->tex_Texture_FogMask = -1;
1283                 p->tex_Texture_Lightmap = -1;
1284                 p->tex_Texture_Deluxemap = -1;
1285                 p->tex_Texture_Attenuation = -1;
1286                 p->tex_Texture_Cube = -1;
1287                 p->tex_Texture_Refraction = -1;
1288                 p->tex_Texture_Reflection = -1;
1289                 p->tex_Texture_ShadowMap2D = -1;
1290                 p->tex_Texture_CubeProjection = -1;
1291                 p->tex_Texture_ScreenNormalMap = -1;
1292                 p->tex_Texture_ScreenDiffuse = -1;
1293                 p->tex_Texture_ScreenSpecular = -1;
1294                 p->tex_Texture_ReflectMask = -1;
1295                 p->tex_Texture_ReflectCube = -1;
1296                 p->tex_Texture_BounceGrid = -1;
1297                 // bind the texture samplers in use
1298                 sampler = 0;
1299                 if (p->loc_Texture_First           >= 0) {p->tex_Texture_First            = sampler;qglUniform1i(p->loc_Texture_First           , sampler);sampler++;}
1300                 if (p->loc_Texture_Second          >= 0) {p->tex_Texture_Second           = sampler;qglUniform1i(p->loc_Texture_Second          , sampler);sampler++;}
1301                 if (p->loc_Texture_GammaRamps      >= 0) {p->tex_Texture_GammaRamps       = sampler;qglUniform1i(p->loc_Texture_GammaRamps      , sampler);sampler++;}
1302                 if (p->loc_Texture_Normal          >= 0) {p->tex_Texture_Normal           = sampler;qglUniform1i(p->loc_Texture_Normal          , sampler);sampler++;}
1303                 if (p->loc_Texture_Color           >= 0) {p->tex_Texture_Color            = sampler;qglUniform1i(p->loc_Texture_Color           , sampler);sampler++;}
1304                 if (p->loc_Texture_Gloss           >= 0) {p->tex_Texture_Gloss            = sampler;qglUniform1i(p->loc_Texture_Gloss           , sampler);sampler++;}
1305                 if (p->loc_Texture_Glow            >= 0) {p->tex_Texture_Glow             = sampler;qglUniform1i(p->loc_Texture_Glow            , sampler);sampler++;}
1306                 if (p->loc_Texture_SecondaryNormal >= 0) {p->tex_Texture_SecondaryNormal  = sampler;qglUniform1i(p->loc_Texture_SecondaryNormal , sampler);sampler++;}
1307                 if (p->loc_Texture_SecondaryColor  >= 0) {p->tex_Texture_SecondaryColor   = sampler;qglUniform1i(p->loc_Texture_SecondaryColor  , sampler);sampler++;}
1308                 if (p->loc_Texture_SecondaryGloss  >= 0) {p->tex_Texture_SecondaryGloss   = sampler;qglUniform1i(p->loc_Texture_SecondaryGloss  , sampler);sampler++;}
1309                 if (p->loc_Texture_SecondaryGlow   >= 0) {p->tex_Texture_SecondaryGlow    = sampler;qglUniform1i(p->loc_Texture_SecondaryGlow   , sampler);sampler++;}
1310                 if (p->loc_Texture_Pants           >= 0) {p->tex_Texture_Pants            = sampler;qglUniform1i(p->loc_Texture_Pants           , sampler);sampler++;}
1311                 if (p->loc_Texture_Shirt           >= 0) {p->tex_Texture_Shirt            = sampler;qglUniform1i(p->loc_Texture_Shirt           , sampler);sampler++;}
1312                 if (p->loc_Texture_FogHeightTexture>= 0) {p->tex_Texture_FogHeightTexture = sampler;qglUniform1i(p->loc_Texture_FogHeightTexture, sampler);sampler++;}
1313                 if (p->loc_Texture_FogMask         >= 0) {p->tex_Texture_FogMask          = sampler;qglUniform1i(p->loc_Texture_FogMask         , sampler);sampler++;}
1314                 if (p->loc_Texture_Lightmap        >= 0) {p->tex_Texture_Lightmap         = sampler;qglUniform1i(p->loc_Texture_Lightmap        , sampler);sampler++;}
1315                 if (p->loc_Texture_Deluxemap       >= 0) {p->tex_Texture_Deluxemap        = sampler;qglUniform1i(p->loc_Texture_Deluxemap       , sampler);sampler++;}
1316                 if (p->loc_Texture_Attenuation     >= 0) {p->tex_Texture_Attenuation      = sampler;qglUniform1i(p->loc_Texture_Attenuation     , sampler);sampler++;}
1317                 if (p->loc_Texture_Cube            >= 0) {p->tex_Texture_Cube             = sampler;qglUniform1i(p->loc_Texture_Cube            , sampler);sampler++;}
1318                 if (p->loc_Texture_Refraction      >= 0) {p->tex_Texture_Refraction       = sampler;qglUniform1i(p->loc_Texture_Refraction      , sampler);sampler++;}
1319                 if (p->loc_Texture_Reflection      >= 0) {p->tex_Texture_Reflection       = sampler;qglUniform1i(p->loc_Texture_Reflection      , sampler);sampler++;}
1320                 if (p->loc_Texture_ShadowMap2D     >= 0) {p->tex_Texture_ShadowMap2D      = sampler;qglUniform1i(p->loc_Texture_ShadowMap2D     , sampler);sampler++;}
1321                 if (p->loc_Texture_CubeProjection  >= 0) {p->tex_Texture_CubeProjection   = sampler;qglUniform1i(p->loc_Texture_CubeProjection  , sampler);sampler++;}
1322                 if (p->loc_Texture_ScreenNormalMap >= 0) {p->tex_Texture_ScreenNormalMap  = sampler;qglUniform1i(p->loc_Texture_ScreenNormalMap , sampler);sampler++;}
1323                 if (p->loc_Texture_ScreenDiffuse   >= 0) {p->tex_Texture_ScreenDiffuse    = sampler;qglUniform1i(p->loc_Texture_ScreenDiffuse   , sampler);sampler++;}
1324                 if (p->loc_Texture_ScreenSpecular  >= 0) {p->tex_Texture_ScreenSpecular   = sampler;qglUniform1i(p->loc_Texture_ScreenSpecular  , sampler);sampler++;}
1325                 if (p->loc_Texture_ReflectMask     >= 0) {p->tex_Texture_ReflectMask      = sampler;qglUniform1i(p->loc_Texture_ReflectMask     , sampler);sampler++;}
1326                 if (p->loc_Texture_ReflectCube     >= 0) {p->tex_Texture_ReflectCube      = sampler;qglUniform1i(p->loc_Texture_ReflectCube     , sampler);sampler++;}
1327                 if (p->loc_Texture_BounceGrid      >= 0) {p->tex_Texture_BounceGrid       = sampler;qglUniform1i(p->loc_Texture_BounceGrid      , sampler);sampler++;}
1328                 // get the uniform block indices so we can bind them
1329                 p->ubiloc_Skeletal_Transform12_UniformBlock = -1;
1330 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1331                 p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
1332 #endif
1333                 // clear the uniform block bindings
1334                 p->ubibind_Skeletal_Transform12_UniformBlock = -1;
1335                 // bind the uniform blocks in use
1336                 ubibind = 0;
1337 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1338                 if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;}
1339 #endif
1340                 // we're done compiling and setting up the shader, at least until it is used
1341                 CHECKGLERROR
1342                 Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler);
1343         }
1344         else
1345                 Con_Printf("^1GLSL shader %s failed!  some features may not work properly.\n", permutationname);
1346
1347         // free the strings
1348         if (sourcestring)
1349                 Mem_Free(sourcestring);
1350 }
1351
1352 static void R_SetupShader_SetPermutationGLSL(unsigned int mode, dpuint64 permutation)
1353 {
1354         r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation);
1355         if (r_glsl_permutation != perm)
1356         {
1357                 r_glsl_permutation = perm;
1358                 if (!r_glsl_permutation->program)
1359                 {
1360                         if (!r_glsl_permutation->compiled)
1361                         {
1362                                 Con_DPrintf("Compiling shader mode %u permutation %llx\n", mode, permutation);
1363                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1364                         }
1365                         if (!r_glsl_permutation->program)
1366                         {
1367                                 // remove features until we find a valid permutation
1368                                 int i;
1369                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1370                                 {
1371                                         // reduce i more quickly whenever it would not remove any bits
1372                                         dpuint64 j = 1ll<<(SHADERPERMUTATION_COUNT-1-i);
1373                                         if (!(permutation & j))
1374                                                 continue;
1375                                         permutation -= j;
1376                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1377                                         if (!r_glsl_permutation->compiled)
1378                                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1379                                         if (r_glsl_permutation->program)
1380                                                 break;
1381                                 }
1382                                 if (i >= SHADERPERMUTATION_COUNT)
1383                                 {
1384                                         //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext);
1385                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1386                                         qglUseProgram(0);CHECKGLERROR
1387                                         return; // no bit left to clear, entire mode is broken
1388                                 }
1389                         }
1390                 }
1391                 CHECKGLERROR
1392                 qglUseProgram(r_glsl_permutation->program);CHECKGLERROR
1393         }
1394         if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
1395         if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
1396         if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time);
1397         CHECKGLERROR
1398 }
1399
1400 void R_GLSL_Restart_f(cmd_state_t *cmd)
1401 {
1402         unsigned int i, limit;
1403         switch(vid.renderpath)
1404         {
1405         case RENDERPATH_GL32:
1406         case RENDERPATH_GLES2:
1407                 {
1408                         r_glsl_permutation_t *p;
1409                         r_glsl_permutation = NULL;
1410                         limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
1411                         for (i = 0;i < limit;i++)
1412                         {
1413                                 if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
1414                                 {
1415                                         GL_Backend_FreeProgram(p->program);
1416                                         Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
1417                                 }
1418                         }
1419                         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
1420                 }
1421                 break;
1422         }
1423 }
1424
1425 static void R_GLSL_DumpShader_f(cmd_state_t *cmd)
1426 {
1427         int i, language, mode, dupe;
1428         char *text;
1429         shadermodeinfo_t *modeinfo;
1430         qfile_t *file;
1431
1432         for (language = 0;language < SHADERLANGUAGE_COUNT;language++)
1433         {
1434                 modeinfo = shadermodeinfo[language];
1435                 for (mode = 0;mode < SHADERMODE_COUNT;mode++)
1436                 {
1437                         // don't dump the same file multiple times (most or all shaders come from the same file)
1438                         for (dupe = mode - 1;dupe >= 0;dupe--)
1439                                 if (!strcmp(modeinfo[mode].filename, modeinfo[dupe].filename))
1440                                         break;
1441                         if (dupe >= 0)
1442                                 continue;
1443                         text = modeinfo[mode].builtinstring;
1444                         if (!text)
1445                                 continue;
1446                         file = FS_OpenRealFile(modeinfo[mode].filename, "w", false);
1447                         if (file)
1448                         {
1449                                 FS_Print(file, "/* The engine may define the following macros:\n");
1450                                 FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
1451                                 for (i = 0;i < SHADERMODE_COUNT;i++)
1452                                         FS_Print(file, modeinfo[i].pretext);
1453                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1454                                         FS_Print(file, shaderpermutationinfo[i].pretext);
1455                                 FS_Print(file, "*/\n");
1456                                 FS_Print(file, text);
1457                                 FS_Close(file);
1458                                 Con_Printf("%s written\n", modeinfo[mode].filename);
1459                         }
1460                         else
1461                                 Con_Printf("failed to write to %s\n", modeinfo[mode].filename);
1462                 }
1463         }
1464 }
1465
1466 void R_SetupShader_Generic(rtexture_t *t, qboolean usegamma, qboolean notrippy, qboolean suppresstexalpha)
1467 {
1468         dpuint64 permutation = 0;
1469         if (r_trippy.integer && !notrippy)
1470                 permutation |= SHADERPERMUTATION_TRIPPY;
1471         permutation |= SHADERPERMUTATION_VIEWTINT;
1472         if (t)
1473                 permutation |= SHADERPERMUTATION_DIFFUSE;
1474         if (usegamma && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
1475                 permutation |= SHADERPERMUTATION_GAMMARAMPS;
1476         if (suppresstexalpha)
1477                 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1478         if (vid.allowalphatocoverage)
1479                 GL_AlphaToCoverage(false);
1480         switch (vid.renderpath)
1481         {
1482         case RENDERPATH_GL32:
1483         case RENDERPATH_GLES2:
1484                 R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation);
1485                 if (r_glsl_permutation->tex_Texture_First >= 0)
1486                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First, t);
1487                 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0)
1488                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps);
1489                 break;
1490         }
1491 }
1492
1493 void R_SetupShader_Generic_NoTexture(qboolean usegamma, qboolean notrippy)
1494 {
1495         R_SetupShader_Generic(NULL, usegamma, notrippy, false);
1496 }
1497
1498 void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb, qboolean skeletal)
1499 {
1500         dpuint64 permutation = 0;
1501         if (r_trippy.integer && !notrippy)
1502                 permutation |= SHADERPERMUTATION_TRIPPY;
1503         if (depthrgb)
1504                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1505         if (skeletal)
1506                 permutation |= SHADERPERMUTATION_SKELETAL;
1507
1508         if (vid.allowalphatocoverage)
1509                 GL_AlphaToCoverage(false);
1510         switch (vid.renderpath)
1511         {
1512         case RENDERPATH_GL32:
1513         case RENDERPATH_GLES2:
1514                 R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
1515 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1516                 if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
1517 #endif
1518                 break;
1519         }
1520 }
1521
1522 #define BLENDFUNC_ALLOWS_COLORMOD      1
1523 #define BLENDFUNC_ALLOWS_FOG           2
1524 #define BLENDFUNC_ALLOWS_FOG_HACK0     4
1525 #define BLENDFUNC_ALLOWS_FOG_HACKALPHA 8
1526 #define BLENDFUNC_ALLOWS_ANYFOG        (BLENDFUNC_ALLOWS_FOG | BLENDFUNC_ALLOWS_FOG_HACK0 | BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1527 static int R_BlendFuncFlags(int src, int dst)
1528 {
1529         int r = 0;
1530
1531         // a blendfunc allows colormod if:
1532         // a) it can never keep the destination pixel invariant, or
1533         // b) it can keep the destination pixel invariant, and still can do so if colormodded
1534         // this is to prevent unintended side effects from colormod
1535
1536         // a blendfunc allows fog if:
1537         // blend(fog(src), fog(dst)) == fog(blend(src, dst))
1538         // this is to prevent unintended side effects from fog
1539
1540         // these checks are the output of fogeval.pl
1541
1542         r |= BLENDFUNC_ALLOWS_COLORMOD;
1543         if(src == GL_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1544         if(src == GL_DST_ALPHA && dst == GL_ONE_MINUS_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1545         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1546         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1547         if(src == GL_DST_COLOR && dst == GL_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1548         if(src == GL_DST_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1549         if(src == GL_DST_COLOR && dst == GL_ZERO) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1550         if(src == GL_ONE && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1551         if(src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG_HACKALPHA;
1552         if(src == GL_ONE && dst == GL_ZERO) r |= BLENDFUNC_ALLOWS_FOG;
1553         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1554         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1555         if(src == GL_ONE_MINUS_DST_COLOR && dst == GL_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1556         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1557         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1558         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1559         if(src == GL_ONE_MINUS_SRC_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1560         if(src == GL_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1561         if(src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1562         if(src == GL_ZERO && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG;
1563         if(src == GL_ZERO && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1564
1565         return r;
1566 }
1567
1568 void R_SetupShader_Surface(const float rtlightambient[3], const float rtlightdiffuse[3], const float rtlightspecular[3], rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist, void *surfacewaterplane, qboolean notrippy)
1569 {
1570         // select a permutation of the lighting shader appropriate to this
1571         // combination of texture, entity, light source, and fogging, only use the
1572         // minimum features necessary to avoid wasting rendering time in the
1573         // fragment shader on features that are not being used
1574         dpuint64 permutation = 0;
1575         unsigned int mode = 0;
1576         int blendfuncflags;
1577         texture_t *t = rsurface.texture;
1578         float m16f[16];
1579         matrix4x4_t tempmatrix;
1580         r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
1581         if (r_trippy.integer && !notrippy)
1582                 permutation |= SHADERPERMUTATION_TRIPPY;
1583         if (t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1584                 permutation |= SHADERPERMUTATION_ALPHAKILL;
1585         if (t->currentmaterialflags & MATERIALFLAG_OCCLUDE)
1586                 permutation |= SHADERPERMUTATION_OCCLUDE;
1587         if (t->r_water_waterscroll[0] && t->r_water_waterscroll[1])
1588                 permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
1589         if (rsurfacepass == RSURFPASS_BACKGROUND)
1590         {
1591                 // distorted background
1592                 if (t->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1593                 {
1594                         mode = SHADERMODE_WATER;
1595                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1596                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1597                         if((r_wateralpha.value < 1) && (t->currentmaterialflags & MATERIALFLAG_WATERALPHA))
1598                         {
1599                                 // this is the right thing to do for wateralpha
1600                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1601                                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1602                         }
1603                         else
1604                         {
1605                                 // this is the right thing to do for entity alpha
1606                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1607                                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1608                         }
1609                 }
1610                 else if (t->currentmaterialflags & MATERIALFLAG_REFRACTION)
1611                 {
1612                         mode = SHADERMODE_REFRACTION;
1613                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1614                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1615                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1616                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1617                 }
1618                 else
1619                 {
1620                         mode = SHADERMODE_GENERIC;
1621                         permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL;
1622                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1623                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1624                 }
1625                 if (vid.allowalphatocoverage)
1626                         GL_AlphaToCoverage(false);
1627         }
1628         else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
1629         {
1630                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1631                 {
1632                         switch(t->offsetmapping)
1633                         {
1634                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1635                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1636                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1637                         case OFFSETMAPPING_OFF: break;
1638                         }
1639                 }
1640                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1641                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1642                 // normalmap (deferred prepass), may use alpha test on diffuse
1643                 mode = SHADERMODE_DEFERREDGEOMETRY;
1644                 GL_BlendFunc(GL_ONE, GL_ZERO);
1645                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1646                 if (vid.allowalphatocoverage)
1647                         GL_AlphaToCoverage(false);
1648         }
1649         else if (rsurfacepass == RSURFPASS_RTLIGHT)
1650         {
1651                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1652                 {
1653                         switch(t->offsetmapping)
1654                         {
1655                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1656                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1657                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1658                         case OFFSETMAPPING_OFF: break;
1659                         }
1660                 }
1661                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1662                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1663                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1664                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1665                 // light source
1666                 mode = SHADERMODE_LIGHTSOURCE;
1667                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1668                         permutation |= SHADERPERMUTATION_CUBEFILTER;
1669                 if (VectorLength2(rtlightdiffuse) > 0)
1670                         permutation |= SHADERPERMUTATION_DIFFUSE;
1671                 if (VectorLength2(rtlightspecular) > 0)
1672                         permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1673                 if (r_refdef.fogenabled)
1674                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1675                 if (t->colormapping)
1676                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1677                 if (r_shadow_usingshadowmap2d)
1678                 {
1679                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1680                         if(r_shadow_shadowmapvsdct)
1681                                 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
1682
1683                         if (r_shadow_shadowmap2ddepthbuffer)
1684                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1685                 }
1686                 if (t->reflectmasktexture)
1687                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1688                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1689                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE);
1690                 if (vid.allowalphatocoverage)
1691                         GL_AlphaToCoverage(false);
1692         }
1693         else if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
1694         {
1695                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1696                 {
1697                         switch(t->offsetmapping)
1698                         {
1699                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1700                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1701                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1702                         case OFFSETMAPPING_OFF: break;
1703                         }
1704                 }
1705                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1706                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1707                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1708                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1709                 // directional model lighting
1710                 mode = SHADERMODE_LIGHTDIRECTION;
1711                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1712                         permutation |= SHADERPERMUTATION_GLOW;
1713                 if (VectorLength2(t->render_modellight_diffuse))
1714                         permutation |= SHADERPERMUTATION_DIFFUSE;
1715                 if (VectorLength2(t->render_modellight_specular) > 0)
1716                         permutation |= SHADERPERMUTATION_SPECULAR;
1717                 if (r_refdef.fogenabled)
1718                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1719                 if (t->colormapping)
1720                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1721                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1722                 {
1723                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1724                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1725
1726                         if (r_shadow_shadowmap2ddepthbuffer)
1727                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1728                 }
1729                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1730                         permutation |= SHADERPERMUTATION_REFLECTION;
1731                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1732                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1733                 if (t->reflectmasktexture)
1734                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1735                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1736                 {
1737                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1738                         if (r_shadow_bouncegrid_state.directional)
1739                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1740                 }
1741                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1742                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1743                 // when using alphatocoverage, we don't need alphakill
1744                 if (vid.allowalphatocoverage)
1745                 {
1746                         if (r_transparent_alphatocoverage.integer)
1747                         {
1748                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1749                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1750                         }
1751                         else
1752                                 GL_AlphaToCoverage(false);
1753                 }
1754         }
1755         else
1756         {
1757                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1758                 {
1759                         switch(t->offsetmapping)
1760                         {
1761                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1762                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1763                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1764                         case OFFSETMAPPING_OFF: break;
1765                         }
1766                 }
1767                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1768                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1769                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1770                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1771                 // lightmapped wall
1772                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1773                         permutation |= SHADERPERMUTATION_GLOW;
1774                 if (r_refdef.fogenabled)
1775                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1776                 if (t->colormapping)
1777                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1778                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1779                 {
1780                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1781                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1782
1783                         if (r_shadow_shadowmap2ddepthbuffer)
1784                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1785                 }
1786                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1787                         permutation |= SHADERPERMUTATION_REFLECTION;
1788                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1789                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1790                 if (t->reflectmasktexture)
1791                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1792                 if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
1793                 {
1794                         // deluxemapping (light direction texture)
1795                         if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace)
1796                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1797                         else
1798                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1799                         permutation |= SHADERPERMUTATION_DIFFUSE;
1800                         if (VectorLength2(t->render_lightmap_specular) > 0)
1801                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1802                 }
1803                 else if (r_glsl_deluxemapping.integer >= 2)
1804                 {
1805                         // fake deluxemapping (uniform light direction in tangentspace)
1806                         if (rsurface.uselightmaptexture)
1807                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP;
1808                         else
1809                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR;
1810                         permutation |= SHADERPERMUTATION_DIFFUSE;
1811                         if (VectorLength2(t->render_lightmap_specular) > 0)
1812                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1813                 }
1814                 else if (rsurface.uselightmaptexture)
1815                 {
1816                         // ordinary lightmapping (q1bsp, q3bsp)
1817                         mode = SHADERMODE_LIGHTMAP;
1818                 }
1819                 else
1820                 {
1821                         // ordinary vertex coloring (q3bsp)
1822                         mode = SHADERMODE_VERTEXCOLOR;
1823                 }
1824                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1825                 {
1826                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1827                         if (r_shadow_bouncegrid_state.directional)
1828                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1829                 }
1830                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1831                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1832                 // when using alphatocoverage, we don't need alphakill
1833                 if (vid.allowalphatocoverage)
1834                 {
1835                         if (r_transparent_alphatocoverage.integer)
1836                         {
1837                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1838                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1839                         }
1840                         else
1841                                 GL_AlphaToCoverage(false);
1842                 }
1843         }
1844         if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG))
1845                 permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE);
1846         if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1847                 permutation |= SHADERPERMUTATION_FOGALPHAHACK;
1848         switch(vid.renderpath)
1849         {
1850         case RENDERPATH_GL32:
1851         case RENDERPATH_GLES2:
1852                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | (rsurface.modellightmapcolor4f ? BATCHNEED_ARRAY_VERTEXCOLOR : 0) | BATCHNEED_ARRAY_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_ARRAY_LIGHTMAP : 0) | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
1853                 RSurf_UploadBuffersForBatch();
1854                 // this has to be after RSurf_PrepareVerticesForBatch
1855                 if (rsurface.batchskeletaltransform3x4buffer)
1856                         permutation |= SHADERPERMUTATION_SKELETAL;
1857                 R_SetupShader_SetPermutationGLSL(mode, permutation);
1858 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1859                 if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
1860 #endif
1861                 if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
1862                 if (mode == SHADERMODE_LIGHTSOURCE)
1863                 {
1864                         if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
1865                         if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1866                         if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1867                         if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
1868                         if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
1869                         if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
1870         
1871                         // additive passes are only darkened by fog, not tinted
1872                         if (r_glsl_permutation->loc_FogColor >= 0)
1873                                 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1874                         if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, t->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
1875                 }
1876                 else
1877                 {
1878                         if (mode == SHADERMODE_FLATCOLOR)
1879                         {
1880                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
1881                         }
1882                         else if (mode == SHADERMODE_LIGHTDIRECTION)
1883                         {
1884                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
1885                                 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_modellight_diffuse[0], t->render_modellight_diffuse[1], t->render_modellight_diffuse[2]);
1886                                 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_modellight_specular[0], t->render_modellight_specular[1], t->render_modellight_specular[2]);
1887                                 if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, t->render_rtlight_diffuse[0], t->render_rtlight_diffuse[1], t->render_rtlight_diffuse[2]);
1888                                 if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, t->render_rtlight_specular[0], t->render_rtlight_specular[1], t->render_rtlight_specular[2]);
1889                                 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1890                                 if (r_glsl_permutation->loc_LightDir >= 0) qglUniform3f(r_glsl_permutation->loc_LightDir, t->render_modellight_lightdir[0], t->render_modellight_lightdir[1], t->render_modellight_lightdir[2]);
1891                         }
1892                         else
1893                         {
1894                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_lightmap_ambient[0], t->render_lightmap_ambient[1], t->render_lightmap_ambient[2]);
1895                                 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_lightmap_diffuse[0], t->render_lightmap_diffuse[1], t->render_lightmap_diffuse[2]);
1896                                 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_lightmap_specular[0], t->render_lightmap_specular[1], t->render_lightmap_specular[2]);
1897                                 if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, t->render_rtlight_diffuse[0], t->render_rtlight_diffuse[1], t->render_rtlight_diffuse[2]);
1898                                 if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, t->render_rtlight_specular[0], t->render_rtlight_specular[1], t->render_rtlight_specular[2]);
1899                         }
1900                         // additive passes are only darkened by fog, not tinted
1901                         if (r_glsl_permutation->loc_FogColor >= 0)
1902                         {
1903                                 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
1904                                         qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1905                                 else
1906                                         qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1907                         }
1908                         if (r_glsl_permutation->loc_DistortScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_DistortScaleRefractReflect, r_water_refractdistort.value * t->refractfactor, r_water_refractdistort.value * t->refractfactor, r_water_reflectdistort.value * t->reflectfactor, r_water_reflectdistort.value * t->reflectfactor);
1909                         if (r_glsl_permutation->loc_ScreenScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenScaleRefractReflect, r_fb.water.screenscale[0], r_fb.water.screenscale[1], r_fb.water.screenscale[0], r_fb.water.screenscale[1]);
1910                         if (r_glsl_permutation->loc_ScreenCenterRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenCenterRefractReflect, r_fb.water.screencenter[0], r_fb.water.screencenter[1], r_fb.water.screencenter[0], r_fb.water.screencenter[1]);
1911                         if (r_glsl_permutation->loc_RefractColor >= 0) qglUniform4f(r_glsl_permutation->loc_RefractColor, t->refractcolor4f[0], t->refractcolor4f[1], t->refractcolor4f[2], t->refractcolor4f[3] * t->currentalpha);
1912                         if (r_glsl_permutation->loc_ReflectColor >= 0) qglUniform4f(r_glsl_permutation->loc_ReflectColor, t->reflectcolor4f[0], t->reflectcolor4f[1], t->reflectcolor4f[2], t->reflectcolor4f[3] * t->currentalpha);
1913                         if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, t->reflectmax - t->reflectmin);
1914                         if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, t->reflectmin);
1915                         if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, t->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
1916                         if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
1917                 }
1918                 if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
1919                 if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
1920                 if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
1921                 if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
1922                 {
1923                         if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_modelshadowmap_texturescale[0], r_shadow_modelshadowmap_texturescale[1], r_shadow_modelshadowmap_texturescale[2], r_shadow_modelshadowmap_texturescale[3]);
1924                         if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_modelshadowmap_parameters[0], r_shadow_modelshadowmap_parameters[1], r_shadow_modelshadowmap_parameters[2], r_shadow_modelshadowmap_parameters[3]);
1925                 }
1926                 else
1927                 {
1928                         if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
1929                         if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
1930                 }
1931
1932                 if (r_glsl_permutation->loc_Color_Glow >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Glow, t->render_glowmod[0], t->render_glowmod[1], t->render_glowmod[2]);
1933                 if (r_glsl_permutation->loc_Alpha >= 0) qglUniform1f(r_glsl_permutation->loc_Alpha, t->currentalpha * ((t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? t->r_water_wateralpha : 1));
1934                 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
1935                 if (r_glsl_permutation->loc_Color_Pants >= 0)
1936                 {
1937                         if (t->pantstexture)
1938                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
1939                         else
1940                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
1941                 }
1942                 if (r_glsl_permutation->loc_Color_Shirt >= 0)
1943                 {
1944                         if (t->shirttexture)
1945                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
1946                         else
1947                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
1948                 }
1949                 if (r_glsl_permutation->loc_FogPlane >= 0) qglUniform4f(r_glsl_permutation->loc_FogPlane, rsurface.fogplane[0], rsurface.fogplane[1], rsurface.fogplane[2], rsurface.fogplane[3]);
1950                 if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
1951                 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
1952                 if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
1953                 if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps,
1954                                 r_glsl_offsetmapping_scale.value*t->offsetscale,
1955                                 max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
1956                                 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
1957                                 max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
1958                         );
1959                 if (r_glsl_permutation->loc_OffsetMapping_LodDistance >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer * r_refdef.view.quality);
1960                 if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, t->offsetbias);
1961                 if (r_glsl_permutation->loc_ScreenToDepth >= 0) qglUniform2f(r_glsl_permutation->loc_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
1962                 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
1963                 if (r_glsl_permutation->loc_BounceGridMatrix >= 0) {Matrix4x4_Concat(&tempmatrix, &r_shadow_bouncegrid_state.matrix, &rsurface.matrix);Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BounceGridMatrix, 1, false, m16f);}
1964                 if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
1965
1966                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First            , r_texture_white                                     );
1967                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second           , r_texture_white                                     );
1968                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps       , r_texture_gammaramps                                );
1969                 if (r_glsl_permutation->tex_Texture_Normal          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal           , t->nmaptexture                       );
1970                 if (r_glsl_permutation->tex_Texture_Color           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color            , t->basetexture                       );
1971                 if (r_glsl_permutation->tex_Texture_Gloss           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss            , t->glosstexture                      );
1972                 if (r_glsl_permutation->tex_Texture_Glow            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow             , t->glowtexture                       );
1973                 if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal  , t->backgroundnmaptexture             );
1974                 if (r_glsl_permutation->tex_Texture_SecondaryColor  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor   , t->backgroundbasetexture             );
1975                 if (r_glsl_permutation->tex_Texture_SecondaryGloss  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss   , t->backgroundglosstexture            );
1976                 if (r_glsl_permutation->tex_Texture_SecondaryGlow   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow    , t->backgroundglowtexture             );
1977                 if (r_glsl_permutation->tex_Texture_Pants           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants            , t->pantstexture                      );
1978                 if (r_glsl_permutation->tex_Texture_Shirt           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt            , t->shirttexture                      );
1979                 if (r_glsl_permutation->tex_Texture_ReflectMask     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask      , t->reflectmasktexture                );
1980                 if (r_glsl_permutation->tex_Texture_ReflectCube     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube      , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
1981                 if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture                          );
1982                 if (r_glsl_permutation->tex_Texture_FogMask         >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask          , r_texture_fogattenuation                            );
1983                 if (r_glsl_permutation->tex_Texture_Lightmap        >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap         , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
1984                 if (r_glsl_permutation->tex_Texture_Deluxemap       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Deluxemap        , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap);
1985                 if (r_glsl_permutation->tex_Texture_Attenuation     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation      , r_shadow_attenuationgradienttexture                 );
1986                 if (rsurfacepass == RSURFPASS_BACKGROUND)
1987                 {
1988                         if (r_glsl_permutation->tex_Texture_Refraction  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Refraction        , waterplane->rt_refraction ? waterplane->rt_refraction->colortexture[0] : r_texture_black);
1989                         if (r_glsl_permutation->tex_Texture_First       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First             , waterplane->rt_camera ? waterplane->rt_camera->colortexture[0] : r_texture_black);
1990                         if (r_glsl_permutation->tex_Texture_Reflection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection        , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
1991                 }
1992                 else
1993                 {
1994                         if (r_glsl_permutation->tex_Texture_Reflection >= 0 && waterplane) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection        , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
1995                 }
1996                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap   , r_shadow_prepassgeometrynormalmaptexture            );
1997                 if (r_glsl_permutation->tex_Texture_ScreenDiffuse   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse     , r_shadow_prepasslightingdiffusetexture              );
1998                 if (r_glsl_permutation->tex_Texture_ScreenSpecular  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular    , r_shadow_prepasslightingspeculartexture             );
1999                 if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
2000                 {
2001                         if (r_glsl_permutation->tex_Texture_ShadowMap2D     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture                           );
2002                         if (rsurface.rtlight)
2003                         {
2004                                 if (r_glsl_permutation->tex_Texture_Cube            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube              , rsurface.rtlight->currentcubemap                    );
2005                                 if (r_glsl_permutation->tex_Texture_CubeProjection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection    , r_shadow_shadowmapvsdcttexture                      );
2006                         }
2007                 }
2008                 if (r_glsl_permutation->tex_Texture_BounceGrid  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
2009                 CHECKGLERROR
2010                 break;
2011         }
2012 }
2013
2014 void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
2015 {
2016         // select a permutation of the lighting shader appropriate to this
2017         // combination of texture, entity, light source, and fogging, only use the
2018         // minimum features necessary to avoid wasting rendering time in the
2019         // fragment shader on features that are not being used
2020         dpuint64 permutation = 0;
2021         unsigned int mode = 0;
2022         const float *lightcolorbase = rtlight->currentcolor;
2023         float ambientscale = rtlight->ambientscale;
2024         float diffusescale = rtlight->diffusescale;
2025         float specularscale = rtlight->specularscale;
2026         // this is the location of the light in view space
2027         vec3_t viewlightorigin;
2028         // this transforms from view space (camera) to light space (cubemap)
2029         matrix4x4_t viewtolight;
2030         matrix4x4_t lighttoview;
2031         float viewtolight16f[16];
2032         // light source
2033         mode = SHADERMODE_DEFERREDLIGHTSOURCE;
2034         if (rtlight->currentcubemap != r_texture_whitecube)
2035                 permutation |= SHADERPERMUTATION_CUBEFILTER;
2036         if (diffusescale > 0)
2037                 permutation |= SHADERPERMUTATION_DIFFUSE;
2038         if (specularscale > 0 && r_shadow_gloss.integer > 0)
2039                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2040         if (r_shadow_usingshadowmap2d)
2041         {
2042                 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
2043                 if (r_shadow_shadowmapvsdct)
2044                         permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
2045
2046                 if (r_shadow_shadowmap2ddepthbuffer)
2047                         permutation |= SHADERPERMUTATION_DEPTHRGB;
2048         }
2049         if (vid.allowalphatocoverage)
2050                 GL_AlphaToCoverage(false);
2051         Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
2052         Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
2053         Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
2054         Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
2055         switch(vid.renderpath)
2056         {
2057         case RENDERPATH_GL32:
2058         case RENDERPATH_GLES2:
2059                 R_SetupShader_SetPermutationGLSL(mode, permutation);
2060                 if (r_glsl_permutation->loc_LightPosition             >= 0) qglUniform3f(       r_glsl_permutation->loc_LightPosition            , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
2061                 if (r_glsl_permutation->loc_ViewToLight               >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight              , 1, false, viewtolight16f);
2062                 if (r_glsl_permutation->loc_DeferredColor_Ambient     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Ambient    , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
2063                 if (r_glsl_permutation->loc_DeferredColor_Diffuse     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
2064                 if (r_glsl_permutation->loc_DeferredColor_Specular    >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Specular   , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
2065                 if (r_glsl_permutation->loc_ShadowMap_TextureScale    >= 0) qglUniform4f(       r_glsl_permutation->loc_ShadowMap_TextureScale   , r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
2066                 if (r_glsl_permutation->loc_ShadowMap_Parameters      >= 0) qglUniform4f(       r_glsl_permutation->loc_ShadowMap_Parameters     , r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
2067                 if (r_glsl_permutation->loc_SpecularPower             >= 0) qglUniform1f(       r_glsl_permutation->loc_SpecularPower            , (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
2068                 if (r_glsl_permutation->loc_ScreenToDepth             >= 0) qglUniform2f(       r_glsl_permutation->loc_ScreenToDepth            , r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
2069                 if (r_glsl_permutation->loc_PixelToScreenTexCoord     >= 0) qglUniform2f(       r_glsl_permutation->loc_PixelToScreenTexCoord    , 1.0f/vid.width, 1.0f/vid.height);
2070
2071                 if (r_glsl_permutation->tex_Texture_Attenuation       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation        , r_shadow_attenuationgradienttexture                 );
2072                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap    , r_shadow_prepassgeometrynormalmaptexture            );
2073                 if (r_glsl_permutation->tex_Texture_Cube              >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube               , rsurface.rtlight->currentcubemap                    );
2074                 if (r_glsl_permutation->tex_Texture_ShadowMap2D       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D        , r_shadow_shadowmap2ddepthtexture                    );
2075                 if (r_glsl_permutation->tex_Texture_CubeProjection    >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection     , r_shadow_shadowmapvsdcttexture                      );
2076                 break;
2077         }
2078 }
2079
2080 #define SKINFRAME_HASH 1024
2081
2082 typedef struct
2083 {
2084         unsigned int loadsequence; // incremented each level change
2085         memexpandablearray_t array;
2086         skinframe_t *hash[SKINFRAME_HASH];
2087 }
2088 r_skinframe_t;
2089 r_skinframe_t r_skinframe;
2090
2091 void R_SkinFrame_PrepareForPurge(void)
2092 {
2093         r_skinframe.loadsequence++;
2094         // wrap it without hitting zero
2095         if (r_skinframe.loadsequence >= 200)
2096                 r_skinframe.loadsequence = 1;
2097 }
2098
2099 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
2100 {
2101         if (!skinframe)
2102                 return;
2103         // mark the skinframe as used for the purging code
2104         skinframe->loadsequence = r_skinframe.loadsequence;
2105 }
2106
2107 void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
2108 {
2109         if (s == NULL)
2110                 return;
2111         if (s->merged == s->base)
2112                 s->merged = NULL;
2113         R_PurgeTexture(s->stain); s->stain = NULL;
2114         R_PurgeTexture(s->merged); s->merged = NULL;
2115         R_PurgeTexture(s->base); s->base = NULL;
2116         R_PurgeTexture(s->pants); s->pants = NULL;
2117         R_PurgeTexture(s->shirt); s->shirt = NULL;
2118         R_PurgeTexture(s->nmap); s->nmap = NULL;
2119         R_PurgeTexture(s->gloss); s->gloss = NULL;
2120         R_PurgeTexture(s->glow); s->glow = NULL;
2121         R_PurgeTexture(s->fog); s->fog = NULL;
2122         R_PurgeTexture(s->reflect); s->reflect = NULL;
2123         s->loadsequence = 0;
2124 }
2125
2126 void R_SkinFrame_Purge(void)
2127 {
2128         int i;
2129         skinframe_t *s;
2130         for (i = 0;i < SKINFRAME_HASH;i++)
2131         {
2132                 for (s = r_skinframe.hash[i];s;s = s->next)
2133                 {
2134                         if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
2135                                 R_SkinFrame_PurgeSkinFrame(s);
2136                 }
2137         }
2138 }
2139
2140 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
2141         skinframe_t *item;
2142         char basename[MAX_QPATH];
2143
2144         Image_StripImageExtension(name, basename, sizeof(basename));
2145
2146         if( last == NULL ) {
2147                 int hashindex;
2148                 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2149                 item = r_skinframe.hash[hashindex];
2150         } else {
2151                 item = last->next;
2152         }
2153
2154         // linearly search through the hash bucket
2155         for( ; item ; item = item->next ) {
2156                 if( !strcmp( item->basename, basename ) ) {
2157                         return item;
2158                 }
2159         }
2160         return NULL;
2161 }
2162
2163 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add)
2164 {
2165         skinframe_t *item;
2166         int compareflags = textureflags & TEXF_IMPORTANTBITS;
2167         int hashindex;
2168         char basename[MAX_QPATH];
2169
2170         Image_StripImageExtension(name, basename, sizeof(basename));
2171
2172         hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2173         for (item = r_skinframe.hash[hashindex];item;item = item->next)
2174                 if (!strcmp(item->basename, basename) &&
2175                         item->textureflags == compareflags &&
2176                         item->comparewidth == comparewidth &&
2177                         item->compareheight == compareheight &&
2178                         item->comparecrc == comparecrc)
2179                         break;
2180
2181         if (!item)
2182         {
2183                 if (!add)
2184                         return NULL;
2185                 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
2186                 memset(item, 0, sizeof(*item));
2187                 strlcpy(item->basename, basename, sizeof(item->basename));
2188                 item->textureflags = compareflags;
2189                 item->comparewidth = comparewidth;
2190                 item->compareheight = compareheight;
2191                 item->comparecrc = comparecrc;
2192                 item->next = r_skinframe.hash[hashindex];
2193                 r_skinframe.hash[hashindex] = item;
2194         }
2195         else if (textureflags & TEXF_FORCE_RELOAD)
2196                 R_SkinFrame_PurgeSkinFrame(item);
2197
2198         R_SkinFrame_MarkUsed(item);
2199         return item;
2200 }
2201
2202 #define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
2203         { \
2204                 unsigned long long avgcolor[5], wsum; \
2205                 int pix, comp, w; \
2206                 avgcolor[0] = 0; \
2207                 avgcolor[1] = 0; \
2208                 avgcolor[2] = 0; \
2209                 avgcolor[3] = 0; \
2210                 avgcolor[4] = 0; \
2211                 wsum = 0; \
2212                 for(pix = 0; pix < cnt; ++pix) \
2213                 { \
2214                         w = 0; \
2215                         for(comp = 0; comp < 3; ++comp) \
2216                                 w += getpixel; \
2217                         if(w) /* ignore perfectly black pixels because that is better for model skins */ \
2218                         { \
2219                                 ++wsum; \
2220                                 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2221                                 w = getpixel; \
2222                                 for(comp = 0; comp < 3; ++comp) \
2223                                         avgcolor[comp] += getpixel * w; \
2224                                 avgcolor[3] += w; \
2225                         } \
2226                         /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2227                         avgcolor[4] += getpixel; \
2228                 } \
2229                 if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
2230                         avgcolor[3] = 1; \
2231                 skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
2232                 skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
2233                 skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
2234                 skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
2235         }
2236
2237 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2238 {
2239         skinframe_t *skinframe;
2240
2241         if (cls.state == ca_dedicated)
2242                 return NULL;
2243
2244         // return an existing skinframe if already loaded
2245         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
2246         if (skinframe && skinframe->base)
2247                 return skinframe;
2248
2249         // if the skinframe doesn't exist this will create it
2250         return R_SkinFrame_LoadExternal_SkinFrame(skinframe, name, textureflags, complain, fallbacknotexture);
2251 }
2252
2253 extern cvar_t gl_picmip;
2254 skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2255 {
2256         int j;
2257         unsigned char *pixels;
2258         unsigned char *bumppixels;
2259         unsigned char *basepixels = NULL;
2260         int basepixels_width = 0;
2261         int basepixels_height = 0;
2262         rtexture_t *ddsbase = NULL;
2263         qboolean ddshasalpha = false;
2264         float ddsavgcolor[4];
2265         char basename[MAX_QPATH];
2266         int miplevel = R_PicmipForFlags(textureflags);
2267         int savemiplevel = miplevel;
2268         int mymiplevel;
2269         char vabuf[1024];
2270
2271         if (cls.state == ca_dedicated)
2272                 return NULL;
2273
2274         Image_StripImageExtension(name, basename, sizeof(basename));
2275
2276         // check for DDS texture file first
2277         if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2278         {
2279                 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2280                 if (basepixels == NULL && fallbacknotexture)
2281                         basepixels = Image_GenerateNoTexture();
2282                 if (basepixels == NULL)
2283                         return NULL;
2284         }
2285
2286         // FIXME handle miplevel
2287
2288         if (developer_loading.integer)
2289                 Con_Printf("loading skin \"%s\"\n", name);
2290
2291         // we've got some pixels to store, so really allocate this new texture now
2292         if (!skinframe)
2293                 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2294         textureflags &= ~TEXF_FORCE_RELOAD;
2295         skinframe->stain = NULL;
2296         skinframe->merged = NULL;
2297         skinframe->base = NULL;
2298         skinframe->pants = NULL;
2299         skinframe->shirt = NULL;
2300         skinframe->nmap = NULL;
2301         skinframe->gloss = NULL;
2302         skinframe->glow = NULL;
2303         skinframe->fog = NULL;
2304         skinframe->reflect = NULL;
2305         skinframe->hasalpha = false;
2306         // we could store the q2animname here too
2307
2308         if (ddsbase)
2309         {
2310                 skinframe->base = ddsbase;
2311                 skinframe->hasalpha = ddshasalpha;
2312                 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2313                 if (r_loadfog && skinframe->hasalpha)
2314                         skinframe->fog = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), false, textureflags | TEXF_ALPHA, NULL, NULL, miplevel, true);
2315                 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2316         }
2317         else
2318         {
2319                 basepixels_width = image_width;
2320                 basepixels_height = image_height;
2321                 skinframe->base = R_LoadTexture2D (r_main_texturepool, skinframe->basename, basepixels_width, basepixels_height, basepixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL);
2322                 if (textureflags & TEXF_ALPHA)
2323                 {
2324                         for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2325                         {
2326                                 if (basepixels[j] < 255)
2327                                 {
2328                                         skinframe->hasalpha = true;
2329                                         break;
2330                                 }
2331                         }
2332                         if (r_loadfog && skinframe->hasalpha)
2333                         {
2334                                 // has transparent pixels
2335                                 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2336                                 for (j = 0;j < image_width * image_height * 4;j += 4)
2337                                 {
2338                                         pixels[j+0] = 255;
2339                                         pixels[j+1] = 255;
2340                                         pixels[j+2] = 255;
2341                                         pixels[j+3] = basepixels[j+3];
2342                                 }
2343                                 skinframe->fog = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_mask", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL);
2344                                 Mem_Free(pixels);
2345                         }
2346                 }
2347                 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2348 #ifndef USE_GLES2
2349                 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2350                 if (r_savedds && skinframe->base)
2351                         R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2352                 if (r_savedds && skinframe->fog)
2353                         R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2354 #endif
2355         }
2356
2357         if (r_loaddds)
2358         {
2359                 mymiplevel = savemiplevel;
2360                 if (r_loadnormalmap)
2361                         skinframe->nmap = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), false, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), NULL, NULL, mymiplevel, true);
2362                 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2363                 if (r_loadgloss)
2364                         skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2365                 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2366                 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2367                 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2368         }
2369
2370         // _norm is the name used by tenebrae and has been adopted as standard
2371         if (r_loadnormalmap && skinframe->nmap == NULL)
2372         {
2373                 mymiplevel = savemiplevel;
2374                 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2375                 {
2376                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2377                         Mem_Free(pixels);
2378                         pixels = NULL;
2379                 }
2380                 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2381                 {
2382                         pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2383                         Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2384                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2385                         Mem_Free(pixels);
2386                         Mem_Free(bumppixels);
2387                 }
2388                 else if (r_shadow_bumpscale_basetexture.value > 0)
2389                 {
2390                         pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2391                         Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2392                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), basepixels_width, basepixels_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2393                         Mem_Free(pixels);
2394                 }
2395 #ifndef USE_GLES2
2396                 if (r_savedds && skinframe->nmap)
2397                         R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2398 #endif
2399         }
2400
2401         // _luma is supported only for tenebrae compatibility
2402         // _glow is the preferred name
2403         mymiplevel = savemiplevel;
2404         if (skinframe->glow == NULL && ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_glow",  skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_luma", skinframe->basename), false, false, false, &mymiplevel))))
2405         {
2406                 skinframe->glow = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_glow.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2407 #ifndef USE_GLES2
2408                 if (r_savedds && skinframe->glow)
2409                         R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2410 #endif
2411                 Mem_Free(pixels);pixels = NULL;
2412         }
2413
2414         mymiplevel = savemiplevel;
2415         if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2416         {
2417                 skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (gl_texturecompression_gloss.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2418 #ifndef USE_GLES2
2419                 if (r_savedds && skinframe->gloss)
2420                         R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2421 #endif
2422                 Mem_Free(pixels);
2423                 pixels = NULL;
2424         }
2425
2426         mymiplevel = savemiplevel;
2427         if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2428         {
2429                 skinframe->pants = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2430 #ifndef USE_GLES2
2431                 if (r_savedds && skinframe->pants)
2432                         R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2433 #endif
2434                 Mem_Free(pixels);
2435                 pixels = NULL;
2436         }
2437
2438         mymiplevel = savemiplevel;
2439         if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2440         {
2441                 skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2442 #ifndef USE_GLES2
2443                 if (r_savedds && skinframe->shirt)
2444                         R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2445 #endif
2446                 Mem_Free(pixels);
2447                 pixels = NULL;
2448         }
2449
2450         mymiplevel = savemiplevel;
2451         if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2452         {
2453                 skinframe->reflect = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_reflectmask.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2454 #ifndef USE_GLES2
2455                 if (r_savedds && skinframe->reflect)
2456                         R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2457 #endif
2458                 Mem_Free(pixels);
2459                 pixels = NULL;
2460         }
2461
2462         if (basepixels)
2463                 Mem_Free(basepixels);
2464
2465         return skinframe;
2466 }
2467
2468 skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, int comparewidth, int compareheight, int comparecrc, qboolean sRGB)
2469 {
2470         int i;
2471         skinframe_t *skinframe;
2472         char vabuf[1024];
2473
2474         if (cls.state == ca_dedicated)
2475                 return NULL;
2476
2477         // if already loaded just return it, otherwise make a new skinframe
2478         skinframe = R_SkinFrame_Find(name, textureflags, comparewidth, compareheight, comparecrc, true);
2479         if (skinframe->base)
2480                 return skinframe;
2481         textureflags &= ~TEXF_FORCE_RELOAD;
2482
2483         skinframe->stain = NULL;
2484         skinframe->merged = NULL;
2485         skinframe->base = NULL;
2486         skinframe->pants = NULL;
2487         skinframe->shirt = NULL;
2488         skinframe->nmap = NULL;
2489         skinframe->gloss = NULL;
2490         skinframe->glow = NULL;
2491         skinframe->fog = NULL;
2492         skinframe->reflect = NULL;
2493         skinframe->hasalpha = false;
2494
2495         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2496         if (!skindata)
2497                 return NULL;
2498
2499         if (developer_loading.integer)
2500                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2501
2502         if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2503         {
2504                 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2505                 unsigned char *b = a + width * height * 4;
2506                 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2507                 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, b, TEXTYPE_BGRA, (textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
2508                 Mem_Free(a);
2509         }
2510         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2511         if (textureflags & TEXF_ALPHA)
2512         {
2513                 for (i = 3;i < width * height * 4;i += 4)
2514                 {
2515                         if (skindata[i] < 255)
2516                         {
2517                                 skinframe->hasalpha = true;
2518                                 break;
2519                         }
2520                 }
2521                 if (r_loadfog && skinframe->hasalpha)
2522                 {
2523                         unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2524                         memcpy(fogpixels, skindata, width * height * 4);
2525                         for (i = 0;i < width * height * 4;i += 4)
2526                                 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2527                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2528                         Mem_Free(fogpixels);
2529                 }
2530         }
2531
2532         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2533         //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2534
2535         return skinframe;
2536 }
2537
2538 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2539 {
2540         int i;
2541         int featuresmask;
2542         skinframe_t *skinframe;
2543
2544         if (cls.state == ca_dedicated)
2545                 return NULL;
2546
2547         // if already loaded just return it, otherwise make a new skinframe
2548         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2549         if (skinframe->base)
2550                 return skinframe;
2551         //textureflags &= ~TEXF_FORCE_RELOAD;
2552
2553         skinframe->stain = NULL;
2554         skinframe->merged = NULL;
2555         skinframe->base = NULL;
2556         skinframe->pants = NULL;
2557         skinframe->shirt = NULL;
2558         skinframe->nmap = NULL;
2559         skinframe->gloss = NULL;
2560         skinframe->glow = NULL;
2561         skinframe->fog = NULL;
2562         skinframe->reflect = NULL;
2563         skinframe->hasalpha = false;
2564
2565         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2566         if (!skindata)
2567                 return NULL;
2568
2569         if (developer_loading.integer)
2570                 Con_Printf("loading quake skin \"%s\"\n", name);
2571
2572         // we actually don't upload anything until the first use, because mdl skins frequently go unused, and are almost never used in both modes (colormapped and non-colormapped)
2573         skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2574         memcpy(skinframe->qpixels, skindata, width*height);
2575         skinframe->qwidth = width;
2576         skinframe->qheight = height;
2577
2578         featuresmask = 0;
2579         for (i = 0;i < width * height;i++)
2580                 featuresmask |= palette_featureflags[skindata[i]];
2581
2582         skinframe->hasalpha = false;
2583         // fence textures
2584         if (name[0] == '{')
2585                 skinframe->hasalpha = true;
2586         skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2587         skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2588         skinframe->qgeneratemerged = true;
2589         skinframe->qgeneratebase = skinframe->qhascolormapping;
2590         skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2591
2592         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2593         //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2594
2595         return skinframe;
2596 }
2597
2598 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboolean colormapped)
2599 {
2600         int width;
2601         int height;
2602         unsigned char *skindata;
2603         char vabuf[1024];
2604
2605         if (!skinframe->qpixels)
2606                 return;
2607
2608         if (!skinframe->qhascolormapping)
2609                 colormapped = false;
2610
2611         if (colormapped)
2612         {
2613                 if (!skinframe->qgeneratebase)
2614                         return;
2615         }
2616         else
2617         {
2618                 if (!skinframe->qgeneratemerged)
2619                         return;
2620         }
2621
2622         width = skinframe->qwidth;
2623         height = skinframe->qheight;
2624         skindata = skinframe->qpixels;
2625
2626         if (skinframe->qgeneratenmap)
2627         {
2628                 unsigned char *a, *b;
2629                 skinframe->qgeneratenmap = false;
2630                 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2631                 b = a + width * height * 4;
2632                 // use either a custom palette or the quake palette
2633                 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2634                 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2635                 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, b, TEXTYPE_BGRA, (skinframe->textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
2636                 Mem_Free(a);
2637         }
2638
2639         if (skinframe->qgenerateglow)
2640         {
2641                 skinframe->qgenerateglow = false;
2642                 if (skinframe->hasalpha) // fence textures
2643                         skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags | TEXF_ALPHA, -1, palette_bgra_onlyfullbrights_transparent); // glow
2644                 else
2645                         skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_onlyfullbrights); // glow
2646         }
2647
2648         if (colormapped)
2649         {
2650                 skinframe->qgeneratebase = false;
2651                 skinframe->base  = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nospecial", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nocolormapnofullbrights : palette_bgra_nocolormap);
2652                 skinframe->pants = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_pantsaswhite);
2653                 skinframe->shirt = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_shirtaswhite);
2654         }
2655         else
2656         {
2657                 skinframe->qgeneratemerged = false;
2658                 if (skinframe->hasalpha) // fence textures
2659                         skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags | TEXF_ALPHA, -1, skinframe->glow ? palette_bgra_nofullbrights_transparent : palette_bgra_transparent);
2660                 else
2661                         skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nofullbrights : palette_bgra_complete);
2662         }
2663
2664         if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2665         {
2666                 Mem_Free(skinframe->qpixels);
2667                 skinframe->qpixels = NULL;
2668         }
2669 }
2670
2671 skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, const unsigned char *skindata, int width, int height, const unsigned int *palette, const unsigned int *alphapalette)
2672 {
2673         int i;
2674         skinframe_t *skinframe;
2675         char vabuf[1024];
2676
2677         if (cls.state == ca_dedicated)
2678                 return NULL;
2679
2680         // if already loaded just return it, otherwise make a new skinframe
2681         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2682         if (skinframe->base)
2683                 return skinframe;
2684         textureflags &= ~TEXF_FORCE_RELOAD;
2685
2686         skinframe->stain = NULL;
2687         skinframe->merged = NULL;
2688         skinframe->base = NULL;
2689         skinframe->pants = NULL;
2690         skinframe->shirt = NULL;
2691         skinframe->nmap = NULL;
2692         skinframe->gloss = NULL;
2693         skinframe->glow = NULL;
2694         skinframe->fog = NULL;
2695         skinframe->reflect = NULL;
2696         skinframe->hasalpha = false;
2697
2698         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2699         if (!skindata)
2700                 return NULL;
2701
2702         if (developer_loading.integer)
2703                 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2704
2705         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2706         if ((textureflags & TEXF_ALPHA) && alphapalette)
2707         {
2708                 for (i = 0;i < width * height;i++)
2709                 {
2710                         if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2711                         {
2712                                 skinframe->hasalpha = true;
2713                                 break;
2714                         }
2715                 }
2716                 if (r_loadfog && skinframe->hasalpha)
2717                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2718         }
2719
2720         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2721         //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2722
2723         return skinframe;
2724 }
2725
2726 skinframe_t *R_SkinFrame_LoadMissing(void)
2727 {
2728         skinframe_t *skinframe;
2729
2730         if (cls.state == ca_dedicated)
2731                 return NULL;
2732
2733         skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2734         skinframe->stain = NULL;
2735         skinframe->merged = NULL;
2736         skinframe->base = NULL;
2737         skinframe->pants = NULL;
2738         skinframe->shirt = NULL;
2739         skinframe->nmap = NULL;
2740         skinframe->gloss = NULL;
2741         skinframe->glow = NULL;
2742         skinframe->fog = NULL;
2743         skinframe->reflect = NULL;
2744         skinframe->hasalpha = false;
2745
2746         skinframe->avgcolor[0] = rand() / RAND_MAX;
2747         skinframe->avgcolor[1] = rand() / RAND_MAX;
2748         skinframe->avgcolor[2] = rand() / RAND_MAX;
2749         skinframe->avgcolor[3] = 1;
2750
2751         return skinframe;
2752 }
2753
2754 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2755 {
2756         int x, y;
2757         static unsigned char pix[16][16][4];
2758
2759         if (cls.state == ca_dedicated)
2760                 return NULL;
2761
2762         // this makes a light grey/dark grey checkerboard texture
2763         if (!pix[0][0][3])
2764         {
2765                 for (y = 0; y < 16; y++)
2766                 {
2767                         for (x = 0; x < 16; x++)
2768                         {
2769                                 if ((y < 8) ^ (x < 8))
2770                                 {
2771                                         pix[y][x][0] = 128;
2772                                         pix[y][x][1] = 128;
2773                                         pix[y][x][2] = 128;
2774                                         pix[y][x][3] = 255;
2775                                 }
2776                                 else
2777                                 {
2778                                         pix[y][x][0] = 64;
2779                                         pix[y][x][1] = 64;
2780                                         pix[y][x][2] = 64;
2781                                         pix[y][x][3] = 255;
2782                                 }
2783                         }
2784                 }
2785         }
2786
2787         return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, pix[0][0], 16, 16, 0, 0, 0, false);
2788 }
2789
2790 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qboolean sRGB)
2791 {
2792         skinframe_t *skinframe;
2793         if (cls.state == ca_dedicated)
2794                 return NULL;
2795         // if already loaded just return it, otherwise make a new skinframe
2796         skinframe = R_SkinFrame_Find(name, textureflags, width, height, 0, true);
2797         if (skinframe->base)
2798                 return skinframe;
2799         textureflags &= ~TEXF_FORCE_RELOAD;
2800         skinframe->stain = NULL;
2801         skinframe->merged = NULL;
2802         skinframe->base = NULL;
2803         skinframe->pants = NULL;
2804         skinframe->shirt = NULL;
2805         skinframe->nmap = NULL;
2806         skinframe->gloss = NULL;
2807         skinframe->glow = NULL;
2808         skinframe->fog = NULL;
2809         skinframe->reflect = NULL;
2810         skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2811         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2812         if (!tex)
2813                 return NULL;
2814         if (developer_loading.integer)
2815                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2816         skinframe->base = skinframe->merged = tex;
2817         Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2818         return skinframe;
2819 }
2820
2821 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2822 typedef struct suffixinfo_s
2823 {
2824         const char *suffix;
2825         qboolean flipx, flipy, flipdiagonal;
2826 }
2827 suffixinfo_t;
2828 static suffixinfo_t suffix[3][6] =
2829 {
2830         {
2831                 {"px",   false, false, false},
2832                 {"nx",   false, false, false},
2833                 {"py",   false, false, false},
2834                 {"ny",   false, false, false},
2835                 {"pz",   false, false, false},
2836                 {"nz",   false, false, false}
2837         },
2838         {
2839                 {"posx", false, false, false},
2840                 {"negx", false, false, false},
2841                 {"posy", false, false, false},
2842                 {"negy", false, false, false},
2843                 {"posz", false, false, false},
2844                 {"negz", false, false, false}
2845         },
2846         {
2847                 {"rt",    true, false,  true},
2848                 {"lf",   false,  true,  true},
2849                 {"ft",    true,  true, false},
2850                 {"bk",   false, false, false},
2851                 {"up",    true, false,  true},
2852                 {"dn",    true, false,  true}
2853         }
2854 };
2855
2856 static int componentorder[4] = {0, 1, 2, 3};
2857
2858 static rtexture_t *R_LoadCubemap(const char *basename)
2859 {
2860         int i, j, cubemapsize;
2861         unsigned char *cubemappixels, *image_buffer;
2862         rtexture_t *cubemaptexture;
2863         char name[256];
2864         // must start 0 so the first loadimagepixels has no requested width/height
2865         cubemapsize = 0;
2866         cubemappixels = NULL;
2867         cubemaptexture = NULL;
2868         // keep trying different suffix groups (posx, px, rt) until one loads
2869         for (j = 0;j < 3 && !cubemappixels;j++)
2870         {
2871                 // load the 6 images in the suffix group
2872                 for (i = 0;i < 6;i++)
2873                 {
2874                         // generate an image name based on the base and and suffix
2875                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2876                         // load it
2877                         if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
2878                         {
2879                                 // an image loaded, make sure width and height are equal
2880                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
2881                                 {
2882                                         // if this is the first image to load successfully, allocate the cubemap memory
2883                                         if (!cubemappixels && image_width >= 1)
2884                                         {
2885                                                 cubemapsize = image_width;
2886                                                 // note this clears to black, so unavailable sides are black
2887                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2888                                         }
2889                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2890                                         if (cubemappixels)
2891                                                 Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_buffer, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder);
2892                                 }
2893                                 else
2894                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2895                                 // free the image
2896                                 Mem_Free(image_buffer);
2897                         }
2898                 }
2899         }
2900         // if a cubemap loaded, upload it
2901         if (cubemappixels)
2902         {
2903                 if (developer_loading.integer)
2904                         Con_Printf("loading cubemap \"%s\"\n", basename);
2905
2906                 cubemaptexture = R_LoadTextureCubeMap(r_main_texturepool, basename, cubemapsize, cubemappixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, (gl_texturecompression_lightcubemaps.integer && gl_texturecompression.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
2907                 Mem_Free(cubemappixels);
2908         }
2909         else
2910         {
2911                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
2912                 if (developer_loading.integer)
2913                 {
2914                         Con_Printf("(tried tried images ");
2915                         for (j = 0;j < 3;j++)
2916                                 for (i = 0;i < 6;i++)
2917                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2918                         Con_Print(" and was unable to find any of them).\n");
2919                 }
2920         }
2921         return cubemaptexture;
2922 }
2923
2924 rtexture_t *R_GetCubemap(const char *basename)
2925 {
2926         int i;
2927         for (i = 0;i < r_texture_numcubemaps;i++)
2928                 if (r_texture_cubemaps[i] != NULL)
2929                         if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
2930                                 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
2931         if (i >= MAX_CUBEMAPS || !r_main_mempool)
2932                 return r_texture_whitecube;
2933         r_texture_numcubemaps++;
2934         r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
2935         strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
2936         r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
2937         return r_texture_cubemaps[i]->texture;
2938 }
2939
2940 static void R_Main_FreeViewCache(void)
2941 {
2942         if (r_refdef.viewcache.entityvisible)
2943                 Mem_Free(r_refdef.viewcache.entityvisible);
2944         if (r_refdef.viewcache.world_pvsbits)
2945                 Mem_Free(r_refdef.viewcache.world_pvsbits);
2946         if (r_refdef.viewcache.world_leafvisible)
2947                 Mem_Free(r_refdef.viewcache.world_leafvisible);
2948         if (r_refdef.viewcache.world_surfacevisible)
2949                 Mem_Free(r_refdef.viewcache.world_surfacevisible);
2950         memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
2951 }
2952
2953 static void R_Main_ResizeViewCache(void)
2954 {
2955         int numentities = r_refdef.scene.numentities;
2956         int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
2957         int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
2958         int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
2959         int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
2960         if (r_refdef.viewcache.maxentities < numentities)
2961         {
2962                 r_refdef.viewcache.maxentities = numentities;
2963                 if (r_refdef.viewcache.entityvisible)
2964                         Mem_Free(r_refdef.viewcache.entityvisible);
2965                 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
2966         }
2967         if (r_refdef.viewcache.world_numclusters != numclusters)
2968         {
2969                 r_refdef.viewcache.world_numclusters = numclusters;
2970                 r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
2971                 if (r_refdef.viewcache.world_pvsbits)
2972                         Mem_Free(r_refdef.viewcache.world_pvsbits);
2973                 r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
2974         }
2975         if (r_refdef.viewcache.world_numleafs != numleafs)
2976         {
2977                 r_refdef.viewcache.world_numleafs = numleafs;
2978                 if (r_refdef.viewcache.world_leafvisible)
2979                         Mem_Free(r_refdef.viewcache.world_leafvisible);
2980                 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
2981         }
2982         if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
2983         {
2984                 r_refdef.viewcache.world_numsurfaces = numsurfaces;
2985                 if (r_refdef.viewcache.world_surfacevisible)
2986                         Mem_Free(r_refdef.viewcache.world_surfacevisible);
2987                 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
2988         }
2989 }
2990
2991 extern rtexture_t *loadingscreentexture;
2992 static void gl_main_start(void)
2993 {
2994         loadingscreentexture = NULL;
2995         r_texture_blanknormalmap = NULL;
2996         r_texture_white = NULL;
2997         r_texture_grey128 = NULL;
2998         r_texture_black = NULL;
2999         r_texture_whitecube = NULL;
3000         r_texture_normalizationcube = NULL;
3001         r_texture_fogattenuation = NULL;
3002         r_texture_fogheighttexture = NULL;
3003         r_texture_gammaramps = NULL;
3004         r_texture_numcubemaps = 0;
3005         r_uniformbufferalignment = 32;
3006
3007         r_loaddds = r_texture_dds_load.integer != 0;
3008         r_savedds = vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3009
3010         switch(vid.renderpath)
3011         {
3012         case RENDERPATH_GL32:
3013         case RENDERPATH_GLES2:
3014                 Cvar_SetValueQuick(&r_textureunits, MAX_TEXTUREUNITS);
3015                 Cvar_SetValueQuick(&gl_combine, 1);
3016                 Cvar_SetValueQuick(&r_glsl, 1);
3017                 r_loadnormalmap = true;
3018                 r_loadgloss = true;
3019                 r_loadfog = false;
3020 #ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
3021                 qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
3022 #endif
3023                 break;
3024         }
3025
3026         R_AnimCache_Free();
3027         R_FrameData_Reset();
3028         R_BufferData_Reset();
3029
3030         r_numqueries = 0;
3031         r_maxqueries = 0;
3032         memset(r_queries, 0, sizeof(r_queries));
3033
3034         r_qwskincache = NULL;
3035         r_qwskincache_size = 0;
3036
3037         // due to caching of texture_t references, the collision cache must be reset
3038         Collision_Cache_Reset(true);
3039
3040         // set up r_skinframe loading system for textures
3041         memset(&r_skinframe, 0, sizeof(r_skinframe));
3042         r_skinframe.loadsequence = 1;
3043         Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
3044
3045         r_main_texturepool = R_AllocTexturePool();
3046         R_BuildBlankTextures();
3047         R_BuildNoTexture();
3048         R_BuildWhiteCube();
3049         R_BuildNormalizationCube();
3050         r_texture_fogattenuation = NULL;
3051         r_texture_fogheighttexture = NULL;
3052         r_texture_gammaramps = NULL;
3053         //r_texture_fogintensity = NULL;
3054         memset(&r_fb, 0, sizeof(r_fb));
3055         Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
3056         r_glsl_permutation = NULL;
3057         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3058         Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
3059         memset(&r_svbsp, 0, sizeof (r_svbsp));
3060
3061         memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
3062         r_texture_numcubemaps = 0;
3063
3064         r_refdef.fogmasktable_density = 0;
3065
3066 #ifdef __ANDROID__
3067         // For Steelstorm Android
3068         // FIXME CACHE the program and reload
3069         // FIXME see possible combinations for SS:BR android
3070         Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
3071         R_SetupShader_SetPermutationGLSL(0, 12);
3072         R_SetupShader_SetPermutationGLSL(0, 13);
3073         R_SetupShader_SetPermutationGLSL(0, 8388621);
3074         R_SetupShader_SetPermutationGLSL(3, 0);
3075         R_SetupShader_SetPermutationGLSL(3, 2048);
3076         R_SetupShader_SetPermutationGLSL(5, 0);
3077         R_SetupShader_SetPermutationGLSL(5, 2);
3078         R_SetupShader_SetPermutationGLSL(5, 2048);
3079         R_SetupShader_SetPermutationGLSL(5, 8388608);
3080         R_SetupShader_SetPermutationGLSL(11, 1);
3081         R_SetupShader_SetPermutationGLSL(11, 2049);
3082         R_SetupShader_SetPermutationGLSL(11, 8193);
3083         R_SetupShader_SetPermutationGLSL(11, 10241);
3084         Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
3085 #endif
3086 }
3087
3088 static void gl_main_shutdown(void)
3089 {
3090         R_RenderTarget_FreeUnused(true);
3091         Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
3092         R_AnimCache_Free();
3093         R_FrameData_Reset();
3094         R_BufferData_Reset();
3095
3096         R_Main_FreeViewCache();
3097
3098         switch(vid.renderpath)
3099         {
3100         case RENDERPATH_GL32:
3101         case RENDERPATH_GLES2:
3102 #if defined(GL_SAMPLES_PASSED) && !defined(USE_GLES2)
3103                 if (r_maxqueries)
3104                         qglDeleteQueries(r_maxqueries, r_queries);
3105 #endif
3106                 break;
3107         }
3108
3109         r_numqueries = 0;
3110         r_maxqueries = 0;
3111         memset(r_queries, 0, sizeof(r_queries));
3112
3113         r_qwskincache = NULL;
3114         r_qwskincache_size = 0;
3115
3116         // clear out the r_skinframe state
3117         Mem_ExpandableArray_FreeArray(&r_skinframe.array);
3118         memset(&r_skinframe, 0, sizeof(r_skinframe));
3119
3120         if (r_svbsp.nodes)
3121                 Mem_Free(r_svbsp.nodes);
3122         memset(&r_svbsp, 0, sizeof (r_svbsp));
3123         R_FreeTexturePool(&r_main_texturepool);
3124         loadingscreentexture = NULL;
3125         r_texture_blanknormalmap = NULL;
3126         r_texture_white = NULL;
3127         r_texture_grey128 = NULL;
3128         r_texture_black = NULL;
3129         r_texture_whitecube = NULL;
3130         r_texture_normalizationcube = NULL;
3131         r_texture_fogattenuation = NULL;
3132         r_texture_fogheighttexture = NULL;
3133         r_texture_gammaramps = NULL;
3134         r_texture_numcubemaps = 0;
3135         //r_texture_fogintensity = NULL;
3136         memset(&r_fb, 0, sizeof(r_fb));
3137         R_GLSL_Restart_f(&cmd_client);
3138
3139         r_glsl_permutation = NULL;
3140         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3141         Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
3142 }
3143
3144 static void gl_main_newmap(void)
3145 {
3146         // FIXME: move this code to client
3147         char *entities, entname[MAX_QPATH];
3148         if (r_qwskincache)
3149                 Mem_Free(r_qwskincache);
3150         r_qwskincache = NULL;
3151         r_qwskincache_size = 0;
3152         if (cl.worldmodel)
3153         {
3154                 dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension);
3155                 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
3156                 {
3157                         CL_ParseEntityLump(entities);
3158                         Mem_Free(entities);
3159                         return;
3160                 }
3161                 if (cl.worldmodel->brush.entities)
3162                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
3163         }
3164         R_Main_FreeViewCache();
3165
3166         R_FrameData_Reset();
3167         R_BufferData_Reset();
3168 }
3169
3170 void GL_Main_Init(void)
3171 {
3172         int i;
3173         r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
3174         R_InitShaderModeInfo();
3175
3176         Cmd_AddCommand(&cmd_client, "r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
3177         Cmd_AddCommand(&cmd_client, "r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
3178         // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
3179         if (gamemode == GAME_NEHAHRA)
3180         {
3181                 Cvar_RegisterVariable (&gl_fogenable);
3182                 Cvar_RegisterVariable (&gl_fogdensity);
3183                 Cvar_RegisterVariable (&gl_fogred);
3184                 Cvar_RegisterVariable (&gl_foggreen);
3185                 Cvar_RegisterVariable (&gl_fogblue);
3186                 Cvar_RegisterVariable (&gl_fogstart);
3187                 Cvar_RegisterVariable (&gl_fogend);
3188                 Cvar_RegisterVariable (&gl_skyclip);
3189         }
3190         Cvar_RegisterVariable(&r_motionblur);
3191         Cvar_RegisterVariable(&r_damageblur);
3192         Cvar_RegisterVariable(&r_motionblur_averaging);
3193         Cvar_RegisterVariable(&r_motionblur_randomize);
3194         Cvar_RegisterVariable(&r_motionblur_minblur);
3195         Cvar_RegisterVariable(&r_motionblur_maxblur);
3196         Cvar_RegisterVariable(&r_motionblur_velocityfactor);
3197         Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed);
3198         Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed);
3199         Cvar_RegisterVariable(&r_motionblur_mousefactor);
3200         Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed);
3201         Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed);
3202         Cvar_RegisterVariable(&r_depthfirst);
3203         Cvar_RegisterVariable(&r_useinfinitefarclip);
3204         Cvar_RegisterVariable(&r_farclip_base);
3205         Cvar_RegisterVariable(&r_farclip_world);
3206         Cvar_RegisterVariable(&r_nearclip);
3207         Cvar_RegisterVariable(&r_deformvertexes);
3208         Cvar_RegisterVariable(&r_transparent);
3209         Cvar_RegisterVariable(&r_transparent_alphatocoverage);
3210         Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
3211         Cvar_RegisterVariable(&r_transparent_useplanardistance);
3212         Cvar_RegisterVariable(&r_showoverdraw);
3213         Cvar_RegisterVariable(&r_showbboxes);
3214         Cvar_RegisterVariable(&r_showbboxes_client);
3215         Cvar_RegisterVariable(&r_showsurfaces);
3216         Cvar_RegisterVariable(&r_showtris);
3217         Cvar_RegisterVariable(&r_shownormals);
3218         Cvar_RegisterVariable(&r_showlighting);
3219         Cvar_RegisterVariable(&r_showcollisionbrushes);
3220         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
3221         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
3222         Cvar_RegisterVariable(&r_showdisabledepthtest);
3223         Cvar_RegisterVariable(&r_showspriteedges);
3224         Cvar_RegisterVariable(&r_showparticleedges);
3225         Cvar_RegisterVariable(&r_drawportals);
3226         Cvar_RegisterVariable(&r_drawentities);
3227         Cvar_RegisterVariable(&r_draw2d);
3228         Cvar_RegisterVariable(&r_drawworld);
3229         Cvar_RegisterVariable(&r_cullentities_trace);
3230         Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
3231         Cvar_RegisterVariable(&r_cullentities_trace_samples);
3232         Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
3233         Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
3234         Cvar_RegisterVariable(&r_cullentities_trace_expand);
3235         Cvar_RegisterVariable(&r_cullentities_trace_pad);
3236         Cvar_RegisterVariable(&r_cullentities_trace_delay);
3237         Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
3238         Cvar_RegisterVariable(&r_sortentities);
3239         Cvar_RegisterVariable(&r_drawviewmodel);
3240         Cvar_RegisterVariable(&r_drawexteriormodel);
3241         Cvar_RegisterVariable(&r_speeds);
3242         Cvar_RegisterVariable(&r_fullbrights);
3243         Cvar_RegisterVariable(&r_wateralpha);
3244         Cvar_RegisterVariable(&r_dynamic);
3245         Cvar_RegisterVariable(&r_fullbright_directed);
3246         Cvar_RegisterVariable(&r_fullbright_directed_ambient);
3247         Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
3248         Cvar_RegisterVariable(&r_fullbright_directed_pitch);
3249         Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
3250         Cvar_RegisterVariable(&r_fullbright);
3251         Cvar_RegisterVariable(&r_shadows);
3252         Cvar_RegisterVariable(&r_shadows_darken);
3253         Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
3254         Cvar_RegisterVariable(&r_shadows_castfrombmodels);
3255         Cvar_RegisterVariable(&r_shadows_throwdistance);
3256         Cvar_RegisterVariable(&r_shadows_throwdirection);
3257         Cvar_RegisterVariable(&r_shadows_focus);
3258         Cvar_RegisterVariable(&r_shadows_shadowmapscale);
3259         Cvar_RegisterVariable(&r_shadows_shadowmapbias);
3260         Cvar_RegisterVariable(&r_q1bsp_skymasking);
3261         Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
3262         Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
3263         Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
3264         Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
3265         Cvar_RegisterVariable(&r_fog_exp2);
3266         Cvar_RegisterVariable(&r_fog_clear);
3267         Cvar_RegisterVariable(&r_drawfog);
3268         Cvar_RegisterVariable(&r_transparentdepthmasking);
3269         Cvar_RegisterVariable(&r_transparent_sortmindist);
3270         Cvar_RegisterVariable(&r_transparent_sortmaxdist);
3271         Cvar_RegisterVariable(&r_transparent_sortarraysize);
3272         Cvar_RegisterVariable(&r_texture_dds_load);
3273         Cvar_RegisterVariable(&r_texture_dds_save);
3274         Cvar_RegisterVariable(&r_textureunits);
3275         Cvar_RegisterVariable(&gl_combine);
3276         Cvar_RegisterVariable(&r_usedepthtextures);
3277         Cvar_RegisterVariable(&r_viewfbo);
3278         Cvar_RegisterVariable(&r_rendertarget_debug);
3279         Cvar_RegisterVariable(&r_viewscale);
3280         Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3281         Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3282         Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3283         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3284         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3285         Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3286         Cvar_RegisterVariable(&r_glsl);
3287         Cvar_RegisterVariable(&r_glsl_deluxemapping);
3288         Cvar_RegisterVariable(&r_glsl_offsetmapping);
3289         Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3290         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3291         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3292         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3293         Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3294         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3295         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3296         Cvar_RegisterVariable(&r_glsl_postprocess);
3297         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3298         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3299         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3300         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3301         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3302         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3303         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3304         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3305         Cvar_RegisterVariable(&r_celshading);
3306         Cvar_RegisterVariable(&r_celoutlines);
3307
3308         Cvar_RegisterVariable(&r_water);
3309         Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3310         Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3311         Cvar_RegisterVariable(&r_water_clippingplanebias);
3312         Cvar_RegisterVariable(&r_water_refractdistort);
3313         Cvar_RegisterVariable(&r_water_reflectdistort);
3314         Cvar_RegisterVariable(&r_water_scissormode);
3315         Cvar_RegisterVariable(&r_water_lowquality);
3316         Cvar_RegisterVariable(&r_water_hideplayer);
3317
3318         Cvar_RegisterVariable(&r_lerpsprites);
3319         Cvar_RegisterVariable(&r_lerpmodels);
3320         Cvar_RegisterVariable(&r_lerplightstyles);
3321         Cvar_RegisterVariable(&r_waterscroll);
3322         Cvar_RegisterVariable(&r_bloom);
3323         Cvar_RegisterVariable(&r_colorfringe);
3324         Cvar_RegisterVariable(&r_bloom_colorscale);
3325         Cvar_RegisterVariable(&r_bloom_brighten);
3326         Cvar_RegisterVariable(&r_bloom_blur);
3327         Cvar_RegisterVariable(&r_bloom_resolution);
3328         Cvar_RegisterVariable(&r_bloom_colorexponent);
3329         Cvar_RegisterVariable(&r_bloom_colorsubtract);
3330         Cvar_RegisterVariable(&r_bloom_scenebrightness);
3331         Cvar_RegisterVariable(&r_hdr_scenebrightness);
3332         Cvar_RegisterVariable(&r_hdr_glowintensity);
3333         Cvar_RegisterVariable(&r_hdr_irisadaptation);
3334         Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3335         Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3336         Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3337         Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3338         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3339         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3340         Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3341         Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3342         Cvar_RegisterVariable(&developer_texturelogging);
3343         Cvar_RegisterVariable(&gl_lightmaps);
3344         Cvar_RegisterVariable(&r_test);
3345         Cvar_RegisterVariable(&r_batch_multidraw);
3346         Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3347         Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3348         Cvar_RegisterVariable(&r_glsl_skeletal);
3349         Cvar_RegisterVariable(&r_glsl_saturation);
3350         Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3351         Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3352         Cvar_RegisterVariable(&r_framedatasize);
3353         for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3354                 Cvar_RegisterVariable(&r_buffermegs[i]);
3355         Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3356         if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3357                 Cvar_SetValue(&cvars_all, "r_fullbrights", 0);
3358 #ifdef DP_MOBILETOUCH
3359         // GLES devices have terrible depth precision in general, so...
3360         Cvar_SetValueQuick(&r_nearclip, 4);
3361         Cvar_SetValueQuick(&r_farclip_base, 4096);
3362         Cvar_SetValueQuick(&r_farclip_world, 0);
3363         Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3364 #endif
3365         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3366 }
3367
3368 void Render_Init(void)
3369 {
3370         gl_backend_init();
3371         R_Textures_Init();
3372         GL_Main_Init();
3373         Font_Init();
3374         GL_Draw_Init();
3375         R_Shadow_Init();
3376         R_Sky_Init();
3377         GL_Surf_Init();
3378         Sbar_Init();
3379         R_Particles_Init();
3380         R_Explosion_Init();
3381         R_LightningBeams_Init();
3382         Mod_RenderInit();
3383 }
3384
3385 int R_CullBox(const vec3_t mins, const vec3_t maxs)
3386 {
3387         int i;
3388         mplane_t *p;
3389         if (r_trippy.integer)
3390                 return false;
3391         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
3392         {
3393                 p = r_refdef.view.frustum + i;
3394                 switch(p->signbits)
3395                 {
3396                 default:
3397                 case 0:
3398                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3399                                 return true;
3400                         break;
3401                 case 1:
3402                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3403                                 return true;
3404                         break;
3405                 case 2:
3406                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3407                                 return true;
3408                         break;
3409                 case 3:
3410                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3411                                 return true;
3412                         break;
3413                 case 4:
3414                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3415                                 return true;
3416                         break;
3417                 case 5:
3418                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3419                                 return true;
3420                         break;
3421                 case 6:
3422                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3423                                 return true;
3424                         break;
3425                 case 7:
3426                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3427                                 return true;
3428                         break;
3429                 }
3430         }
3431         return false;
3432 }
3433
3434 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3435 {
3436         int i;
3437         const mplane_t *p;
3438         if (r_trippy.integer)
3439                 return false;
3440         for (i = 0;i < numplanes;i++)
3441         {
3442                 p = planes + i;
3443                 switch(p->signbits)
3444                 {
3445                 default:
3446                 case 0:
3447                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3448                                 return true;
3449                         break;
3450                 case 1:
3451                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3452                                 return true;
3453                         break;
3454                 case 2:
3455                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3456                                 return true;
3457                         break;
3458                 case 3:
3459                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3460                                 return true;
3461                         break;
3462                 case 4:
3463                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3464                                 return true;
3465                         break;
3466                 case 5:
3467                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3468                                 return true;
3469                         break;
3470                 case 6:
3471                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3472                                 return true;
3473                         break;
3474                 case 7:
3475                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3476                                 return true;
3477                         break;
3478                 }
3479         }
3480         return false;
3481 }
3482
3483 //==================================================================================
3484
3485 // LadyHavoc: this stores temporary data used within the same frame
3486
3487 typedef struct r_framedata_mem_s
3488 {
3489         struct r_framedata_mem_s *purge; // older mem block to free on next frame
3490         size_t size; // how much usable space
3491         size_t current; // how much space in use
3492         size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3493         size_t wantedsize; // how much space was allocated
3494         unsigned char *data; // start of real data (16byte aligned)
3495 }
3496 r_framedata_mem_t;
3497
3498 static r_framedata_mem_t *r_framedata_mem;
3499
3500 void R_FrameData_Reset(void)
3501 {
3502         while (r_framedata_mem)
3503         {
3504                 r_framedata_mem_t *next = r_framedata_mem->purge;
3505                 Mem_Free(r_framedata_mem);
3506                 r_framedata_mem = next;
3507         }
3508 }
3509
3510 static void R_FrameData_Resize(qboolean mustgrow)
3511 {
3512         size_t wantedsize;
3513         wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3514         wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3515         if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3516         {
3517                 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3518                 newmem->wantedsize = wantedsize;
3519                 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3520                 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3521                 newmem->current = 0;
3522                 newmem->mark = 0;
3523                 newmem->purge = r_framedata_mem;
3524                 r_framedata_mem = newmem;
3525         }
3526 }
3527
3528 void R_FrameData_NewFrame(void)
3529 {
3530         R_FrameData_Resize(false);
3531         if (!r_framedata_mem)
3532                 return;
3533         // if we ran out of space on the last frame, free the old memory now
3534         while (r_framedata_mem->purge)
3535         {
3536                 // repeatedly remove the second item in the list, leaving only head
3537                 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3538                 Mem_Free(r_framedata_mem->purge);
3539                 r_framedata_mem->purge = next;
3540         }
3541         // reset the current mem pointer
3542         r_framedata_mem->current = 0;
3543         r_framedata_mem->mark = 0;
3544 }
3545
3546 void *R_FrameData_Alloc(size_t size)
3547 {
3548         void *data;
3549         float newvalue;
3550
3551         // align to 16 byte boundary - the data pointer is already aligned, so we
3552         // only need to ensure the size of every allocation is also aligned
3553         size = (size + 15) & ~15;
3554
3555         while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3556         {
3557                 // emergency - we ran out of space, allocate more memory
3558                 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3559                 newvalue = r_framedatasize.value * 2.0f;
3560                 // 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
3561                 if (sizeof(size_t) >= 8)
3562                         newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3563                 else
3564                         newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3565                 // this might not be a growing it, but we'll allocate another buffer every time
3566                 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3567                 R_FrameData_Resize(true);
3568         }
3569
3570         data = r_framedata_mem->data + r_framedata_mem->current;
3571         r_framedata_mem->current += size;
3572
3573         // count the usage for stats
3574         r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3575         r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3576
3577         return (void *)data;
3578 }
3579
3580 void *R_FrameData_Store(size_t size, void *data)
3581 {
3582         void *d = R_FrameData_Alloc(size);
3583         if (d && data)
3584                 memcpy(d, data, size);
3585         return d;
3586 }
3587
3588 void R_FrameData_SetMark(void)
3589 {
3590         if (!r_framedata_mem)
3591                 return;
3592         r_framedata_mem->mark = r_framedata_mem->current;
3593 }
3594
3595 void R_FrameData_ReturnToMark(void)
3596 {
3597         if (!r_framedata_mem)
3598                 return;
3599         r_framedata_mem->current = r_framedata_mem->mark;
3600 }
3601
3602 //==================================================================================
3603
3604 // avoid reusing the same buffer objects on consecutive frames
3605 #define R_BUFFERDATA_CYCLE 3
3606
3607 typedef struct r_bufferdata_buffer_s
3608 {
3609         struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3610         size_t size; // how much usable space
3611         size_t current; // how much space in use
3612         r_meshbuffer_t *buffer; // the buffer itself
3613 }
3614 r_bufferdata_buffer_t;
3615
3616 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3617 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3618
3619 /// frees all dynamic buffers
3620 void R_BufferData_Reset(void)
3621 {
3622         int cycle, type;
3623         r_bufferdata_buffer_t **p, *mem;
3624         for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3625         {
3626                 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3627                 {
3628                         // free all buffers
3629                         p = &r_bufferdata_buffer[cycle][type];
3630                         while (*p)
3631                         {
3632                                 mem = *p;
3633                                 *p = (*p)->purge;
3634                                 if (mem->buffer)
3635                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3636                                 Mem_Free(mem);
3637                         }
3638                 }
3639         }
3640 }
3641
3642 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3643 static void R_BufferData_Resize(r_bufferdata_type_t type, qboolean mustgrow, size_t minsize)
3644 {
3645         r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3646         size_t size;
3647         float newvalue = r_buffermegs[type].value;
3648
3649         // increase the cvar if we have to (but only if we already have a mem)
3650         if (mustgrow && mem)
3651                 newvalue *= 2.0f;
3652         newvalue = bound(0.25f, newvalue, 256.0f);
3653         while (newvalue * 1024*1024 < minsize)
3654                 newvalue *= 2.0f;
3655
3656         // clamp the cvar to valid range
3657         newvalue = bound(0.25f, newvalue, 256.0f);
3658         if (r_buffermegs[type].value != newvalue)
3659                 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3660
3661         // calculate size in bytes
3662         size = (size_t)(newvalue * 1024*1024);
3663         size = bound(131072, size, 256*1024*1024);
3664
3665         // allocate a new buffer if the size is different (purge old one later)
3666         // or if we were told we must grow the buffer
3667         if (!mem || mem->size != size || mustgrow)
3668         {
3669                 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3670                 mem->size = size;
3671                 mem->current = 0;
3672                 if (type == R_BUFFERDATA_VERTEX)
3673                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3674                 else if (type == R_BUFFERDATA_INDEX16)
3675                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3676                 else if (type == R_BUFFERDATA_INDEX32)
3677                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3678                 else if (type == R_BUFFERDATA_UNIFORM)
3679                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3680                 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3681                 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3682         }
3683 }
3684
3685 void R_BufferData_NewFrame(void)
3686 {
3687         int type;
3688         r_bufferdata_buffer_t **p, *mem;
3689         // cycle to the next frame's buffers
3690         r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3691         // if we ran out of space on the last time we used these buffers, free the old memory now
3692         for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3693         {
3694                 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3695                 {
3696                         R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3697                         // free all but the head buffer, this is how we recycle obsolete
3698                         // buffers after they are no longer in use
3699                         p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3700                         while (*p)
3701                         {
3702                                 mem = *p;
3703                                 *p = (*p)->purge;
3704                                 if (mem->buffer)
3705                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3706                                 Mem_Free(mem);
3707                         }
3708                         // reset the current offset
3709                         r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3710                 }
3711         }
3712 }
3713
3714 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3715 {
3716         r_bufferdata_buffer_t *mem;
3717         int offset = 0;
3718         int padsize;
3719
3720         *returnbufferoffset = 0;
3721
3722         // align size to a byte boundary appropriate for the buffer type, this
3723         // makes all allocations have aligned start offsets
3724         if (type == R_BUFFERDATA_UNIFORM)
3725                 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3726         else
3727                 padsize = (datasize + 15) & ~15;
3728
3729         // if we ran out of space in this buffer we must allocate a new one
3730         if (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size)
3731                 R_BufferData_Resize(type, true, padsize);
3732
3733         // if the resize did not give us enough memory, fail
3734         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)
3735                 Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3736
3737         mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3738         offset = (int)mem->current;
3739         mem->current += padsize;
3740
3741         // upload the data to the buffer at the chosen offset
3742         if (offset == 0)
3743                 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3744         R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3745
3746         // count the usage for stats
3747         r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3748         r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3749
3750         // return the buffer offset
3751         *returnbufferoffset = offset;
3752
3753         return mem->buffer;
3754 }
3755
3756 //==================================================================================
3757
3758 // LadyHavoc: animcache originally written by Echon, rewritten since then
3759
3760 /**
3761  * Animation cache prevents re-generating mesh data for an animated model
3762  * multiple times in one frame for lighting, shadowing, reflections, etc.
3763  */
3764
3765 void R_AnimCache_Free(void)
3766 {
3767 }
3768
3769 void R_AnimCache_ClearCache(void)
3770 {
3771         int i;
3772         entity_render_t *ent;
3773
3774         for (i = 0;i < r_refdef.scene.numentities;i++)
3775         {
3776                 ent = r_refdef.scene.entities[i];
3777                 ent->animcache_vertex3f = NULL;
3778                 ent->animcache_vertex3f_vertexbuffer = NULL;
3779                 ent->animcache_vertex3f_bufferoffset = 0;
3780                 ent->animcache_normal3f = NULL;
3781                 ent->animcache_normal3f_vertexbuffer = NULL;
3782                 ent->animcache_normal3f_bufferoffset = 0;
3783                 ent->animcache_svector3f = NULL;
3784                 ent->animcache_svector3f_vertexbuffer = NULL;
3785                 ent->animcache_svector3f_bufferoffset = 0;
3786                 ent->animcache_tvector3f = NULL;
3787                 ent->animcache_tvector3f_vertexbuffer = NULL;
3788                 ent->animcache_tvector3f_bufferoffset = 0;
3789                 ent->animcache_skeletaltransform3x4 = NULL;
3790                 ent->animcache_skeletaltransform3x4buffer = NULL;
3791                 ent->animcache_skeletaltransform3x4offset = 0;
3792                 ent->animcache_skeletaltransform3x4size = 0;
3793         }
3794 }
3795
3796 qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
3797 {
3798         dp_model_t *model = ent->model;
3799         int numvertices;
3800
3801         // see if this ent is worth caching
3802         if (!model || !model->Draw || !model->AnimateVertices)
3803                 return false;
3804         // nothing to cache if it contains no animations and has no skeleton
3805         if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3806                 return false;
3807         // see if it is already cached for gpuskeletal
3808         if (ent->animcache_skeletaltransform3x4)
3809                 return false;
3810         // see if it is already cached as a mesh
3811         if (ent->animcache_vertex3f)
3812         {
3813                 // check if we need to add normals or tangents
3814                 if (ent->animcache_normal3f)
3815                         wantnormals = false;
3816                 if (ent->animcache_svector3f)
3817                         wanttangents = false;
3818                 if (!wantnormals && !wanttangents)
3819                         return false;
3820         }
3821
3822         // check which kind of cache we need to generate
3823         if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3824         {
3825                 // cache the skeleton so the vertex shader can use it
3826                 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3827                 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3828                 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3829                 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3830                 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4); 
3831                 // note: this can fail if the buffer is at the grow limit
3832                 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3833                 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3834         }
3835         else if (ent->animcache_vertex3f)
3836         {
3837                 // mesh was already cached but we may need to add normals/tangents
3838                 // (this only happens with multiple views, reflections, cameras, etc)
3839                 if (wantnormals || wanttangents)
3840                 {
3841                         numvertices = model->surfmesh.num_vertices;
3842                         if (wantnormals)
3843                                 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3844                         if (wanttangents)
3845                         {
3846                                 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3847                                 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3848                         }
3849                         model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3850                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3851                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3852                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3853                 }
3854         }
3855         else
3856         {
3857                 // generate mesh cache
3858                 numvertices = model->surfmesh.num_vertices;
3859                 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3860                 if (wantnormals)
3861                         ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3862                 if (wanttangents)
3863                 {
3864                         ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3865                         ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3866                 }
3867                 model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
3868                 if (wantnormals || wanttangents)
3869                 {
3870                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3871                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3872                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3873                 }
3874                 r_refdef.stats[r_stat_animcache_shape_count] += 1;
3875                 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
3876                 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
3877         }
3878         return true;
3879 }
3880
3881 void R_AnimCache_CacheVisibleEntities(void)
3882 {
3883         int i;
3884
3885         // TODO: thread this
3886         // NOTE: R_PrepareRTLights() also caches entities
3887
3888         for (i = 0;i < r_refdef.scene.numentities;i++)
3889                 if (r_refdef.viewcache.entityvisible[i])
3890                         R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
3891 }
3892
3893 //==================================================================================
3894
3895 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)
3896 {
3897         int i;
3898         vec3_t eyemins, eyemaxs;
3899         vec3_t boxmins, boxmaxs;
3900         vec3_t padmins, padmaxs;
3901         vec3_t start;
3902         vec3_t end;
3903         dp_model_t *model = r_refdef.scene.worldmodel;
3904         static vec3_t positions[] = {
3905                 { 0.5f, 0.5f, 0.5f },
3906                 { 0.0f, 0.0f, 0.0f },
3907                 { 0.0f, 0.0f, 1.0f },
3908                 { 0.0f, 1.0f, 0.0f },
3909                 { 0.0f, 1.0f, 1.0f },
3910                 { 1.0f, 0.0f, 0.0f },
3911                 { 1.0f, 0.0f, 1.0f },
3912                 { 1.0f, 1.0f, 0.0f },
3913                 { 1.0f, 1.0f, 1.0f },
3914         };
3915
3916         // sample count can be set to -1 to skip this logic, for flicker-prone objects
3917         if (numsamples < 0)
3918                 return true;
3919
3920         // view origin is not used for culling in portal/reflection/refraction renders or isometric views
3921         if (!r_refdef.view.usevieworiginculling)
3922                 return true;
3923
3924         if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
3925                 return true;
3926
3927         // expand the eye box a little
3928         eyemins[0] = eye[0] - eyejitter;
3929         eyemaxs[0] = eye[0] + eyejitter;
3930         eyemins[1] = eye[1] - eyejitter;
3931         eyemaxs[1] = eye[1] + eyejitter;
3932         eyemins[2] = eye[2] - eyejitter;
3933         eyemaxs[2] = eye[2] + eyejitter;
3934         // expand the box a little
3935         boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
3936         boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
3937         boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
3938         boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
3939         boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
3940         boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
3941         // make an even larger box for the acceptable area
3942         padmins[0] = boxmins[0] - pad;
3943         padmaxs[0] = boxmaxs[0] + pad;
3944         padmins[1] = boxmins[1] - pad;
3945         padmaxs[1] = boxmaxs[1] + pad;
3946         padmins[2] = boxmins[2] - pad;
3947         padmaxs[2] = boxmaxs[2] + pad;
3948
3949         // return true if eye overlaps enlarged box
3950         if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
3951                 return true;
3952
3953         // try specific positions in the box first - note that these can be cached
3954         if (r_cullentities_trace_entityocclusion.integer)
3955         {
3956                 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
3957                 {
3958                         VectorCopy(eye, start);
3959                         end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
3960                         end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
3961                         end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
3962                         //trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
3963                         trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
3964                         // not picky - if the trace ended anywhere in the box we're good
3965                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
3966                                 return true;
3967                 }
3968         }
3969         else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
3970                 return true;
3971
3972         // try various random positions
3973         for (i = 0; i < numsamples; i++)
3974         {
3975                 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
3976                 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
3977                 if (r_cullentities_trace_entityocclusion.integer)
3978                 {
3979                         trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
3980                         // not picky - if the trace ended anywhere in the box we're good
3981                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
3982                                 return true;
3983                 }
3984                 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
3985                         return true;
3986         }
3987
3988         return false;
3989 }
3990
3991
3992 static void R_View_UpdateEntityVisible (void)
3993 {
3994         int i;
3995         int renderimask;
3996         int samples;
3997         entity_render_t *ent;
3998
3999         if (r_refdef.envmap || r_fb.water.hideplayer)
4000                 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
4001         else if (chase_active.integer || r_fb.water.renderingscene)
4002                 renderimask = RENDER_VIEWMODEL;
4003         else
4004                 renderimask = RENDER_EXTERIORMODEL;
4005         if (!r_drawviewmodel.integer)
4006                 renderimask |= RENDER_VIEWMODEL;
4007         if (!r_drawexteriormodel.integer)
4008                 renderimask |= RENDER_EXTERIORMODEL;
4009         memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4010         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4011         {
4012                 // worldmodel can check visibility
4013                 for (i = 0;i < r_refdef.scene.numentities;i++)
4014                 {
4015                         ent = r_refdef.scene.entities[i];
4016                         if (!(ent->flags & renderimask))
4017                         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)))
4018                         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))
4019                                 r_refdef.viewcache.entityvisible[i] = true;
4020                 }
4021         }
4022         else
4023         {
4024                 // no worldmodel or it can't check visibility
4025                 for (i = 0;i < r_refdef.scene.numentities;i++)
4026                 {
4027                         ent = r_refdef.scene.entities[i];
4028                         if (!(ent->flags & renderimask))
4029                         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)))
4030                                 r_refdef.viewcache.entityvisible[i] = true;
4031                 }
4032         }
4033         if (r_cullentities_trace.integer)
4034         {
4035                 for (i = 0;i < r_refdef.scene.numentities;i++)
4036                 {
4037                         if (!r_refdef.viewcache.entityvisible[i])
4038                                 continue;
4039                         ent = r_refdef.scene.entities[i];
4040                         if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4041                         {
4042                                 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4043                                 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))
4044                                         ent->last_trace_visibility = realtime;
4045                                 if (ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
4046                                         r_refdef.viewcache.entityvisible[i] = 0;
4047                         }
4048                 }
4049         }
4050 }
4051
4052 /// only used if skyrendermasked, and normally returns false
4053 static int R_DrawBrushModelsSky (void)
4054 {
4055         int i, sky;
4056         entity_render_t *ent;
4057
4058         sky = false;
4059         for (i = 0;i < r_refdef.scene.numentities;i++)
4060         {
4061                 if (!r_refdef.viewcache.entityvisible[i])
4062                         continue;
4063                 ent = r_refdef.scene.entities[i];
4064                 if (!ent->model || !ent->model->DrawSky)
4065                         continue;
4066                 ent->model->DrawSky(ent);
4067                 sky = true;
4068         }
4069         return sky;
4070 }
4071
4072 static void R_DrawNoModel(entity_render_t *ent);
4073 static void R_DrawModels(void)
4074 {
4075         int i;
4076         entity_render_t *ent;
4077
4078         for (i = 0;i < r_refdef.scene.numentities;i++)
4079         {
4080                 if (!r_refdef.viewcache.entityvisible[i])
4081                         continue;
4082                 ent = r_refdef.scene.entities[i];
4083                 r_refdef.stats[r_stat_entities]++;
4084                 /*
4085                 if (ent->model && !strncmp(ent->model->name, "models/proto_", 13))
4086                 {
4087                         vec3_t f, l, u, o;
4088                         Matrix4x4_ToVectors(&ent->matrix, f, l, u, o);
4089                         Con_Printf("R_DrawModels\n");
4090                         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]);
4091                         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);
4092                         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);
4093                 }
4094                 */
4095                 if (ent->model && ent->model->Draw != NULL)
4096                         ent->model->Draw(ent);
4097                 else
4098                         R_DrawNoModel(ent);
4099         }
4100 }
4101
4102 static void R_DrawModelsDepth(void)
4103 {
4104         int i;
4105         entity_render_t *ent;
4106
4107         for (i = 0;i < r_refdef.scene.numentities;i++)
4108         {
4109                 if (!r_refdef.viewcache.entityvisible[i])
4110                         continue;
4111                 ent = r_refdef.scene.entities[i];
4112                 if (ent->model && ent->model->DrawDepth != NULL)
4113                         ent->model->DrawDepth(ent);
4114         }
4115 }
4116
4117 static void R_DrawModelsDebug(void)
4118 {
4119         int i;
4120         entity_render_t *ent;
4121
4122         for (i = 0;i < r_refdef.scene.numentities;i++)
4123         {
4124                 if (!r_refdef.viewcache.entityvisible[i])
4125                         continue;
4126                 ent = r_refdef.scene.entities[i];
4127                 if (ent->model && ent->model->DrawDebug != NULL)
4128                         ent->model->DrawDebug(ent);
4129         }
4130 }
4131
4132 static void R_DrawModelsAddWaterPlanes(void)
4133 {
4134         int i;
4135         entity_render_t *ent;
4136
4137         for (i = 0;i < r_refdef.scene.numentities;i++)
4138         {
4139                 if (!r_refdef.viewcache.entityvisible[i])
4140                         continue;
4141                 ent = r_refdef.scene.entities[i];
4142                 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4143                         ent->model->DrawAddWaterPlanes(ent);
4144         }
4145 }
4146
4147 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}};
4148
4149 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4150 {
4151         if (r_hdr_irisadaptation.integer)
4152         {
4153                 vec3_t p;
4154                 vec3_t ambient;
4155                 vec3_t diffuse;
4156                 vec3_t diffusenormal;
4157                 vec3_t forward;
4158                 vec_t brightness = 0.0f;
4159                 vec_t goal;
4160                 vec_t current;
4161                 vec_t d;
4162                 int c;
4163                 VectorCopy(r_refdef.view.forward, forward);
4164                 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4165                 {
4166                         p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4167                         p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4168                         p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4169                         R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4170                         d = DotProduct(forward, diffusenormal);
4171                         brightness += VectorLength(ambient);
4172                         if (d > 0)
4173                                 brightness += d * VectorLength(diffuse);
4174                 }
4175                 brightness *= 1.0f / c;
4176                 brightness += 0.00001f; // make sure it's never zero
4177                 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4178                 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4179                 current = r_hdr_irisadaptation_value.value;
4180                 if (current < goal)
4181                         current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4182                 else if (current > goal)
4183                         current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4184                 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4185                         Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4186         }
4187         else if (r_hdr_irisadaptation_value.value != 1.0f)
4188                 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4189 }
4190
4191 static void R_View_SetFrustum(const int *scissor)
4192 {
4193         int i;
4194         double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4195         vec3_t forward, left, up, origin, v;
4196
4197         if(scissor)
4198         {
4199                 // flipped x coordinates (because x points left here)
4200                 fpx =  1.0 - 2.0 * (scissor[0]              - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4201                 fnx =  1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4202                 // non-flipped y coordinates
4203                 fny = -1.0 + 2.0 * (scissor[1]              - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4204                 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4205         }
4206
4207         // we can't trust r_refdef.view.forward and friends in reflected scenes
4208         Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4209
4210 #if 0
4211         r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4212         r_refdef.view.frustum[0].normal[1] = 0 - 0;
4213         r_refdef.view.frustum[0].normal[2] = -1 - 0;
4214         r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4215         r_refdef.view.frustum[1].normal[1] = 0 + 0;
4216         r_refdef.view.frustum[1].normal[2] = -1 + 0;
4217         r_refdef.view.frustum[2].normal[0] = 0 - 0;
4218         r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4219         r_refdef.view.frustum[2].normal[2] = -1 - 0;
4220         r_refdef.view.frustum[3].normal[0] = 0 + 0;
4221         r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4222         r_refdef.view.frustum[3].normal[2] = -1 + 0;
4223 #endif
4224
4225 #if 0
4226         zNear = r_refdef.nearclip;
4227         nudge = 1.0 - 1.0 / (1<<23);
4228         r_refdef.view.frustum[4].normal[0] = 0 - 0;
4229         r_refdef.view.frustum[4].normal[1] = 0 - 0;
4230         r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4231         r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4232         r_refdef.view.frustum[5].normal[0] = 0 + 0;
4233         r_refdef.view.frustum[5].normal[1] = 0 + 0;
4234         r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4235         r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4236 #endif
4237
4238
4239
4240 #if 0
4241         r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4242         r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4243         r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4244         r_refdef.view.frustum[0].dist = m[15] - m[12];
4245
4246         r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4247         r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4248         r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4249         r_refdef.view.frustum[1].dist = m[15] + m[12];
4250
4251         r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4252         r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4253         r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4254         r_refdef.view.frustum[2].dist = m[15] - m[13];
4255
4256         r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4257         r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4258         r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4259         r_refdef.view.frustum[3].dist = m[15] + m[13];
4260
4261         r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4262         r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4263         r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4264         r_refdef.view.frustum[4].dist = m[15] - m[14];
4265
4266         r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4267         r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4268         r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4269         r_refdef.view.frustum[5].dist = m[15] + m[14];
4270 #endif
4271
4272         if (r_refdef.view.useperspective)
4273         {
4274                 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4275                 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]);
4276                 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]);
4277                 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]);
4278                 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]);
4279
4280                 // then the normals from the corners relative to origin
4281                 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4282                 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4283                 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4284                 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4285
4286                 // in a NORMAL view, forward cross left == up
4287                 // in a REFLECTED view, forward cross left == down
4288                 // so our cross products above need to be adjusted for a left handed coordinate system
4289                 CrossProduct(forward, left, v);
4290                 if(DotProduct(v, up) < 0)
4291                 {
4292                         VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4293                         VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4294                         VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4295                         VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4296                 }
4297
4298                 // Leaving those out was a mistake, those were in the old code, and they
4299                 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4300                 // I couldn't reproduce it after adding those normalizations. --blub
4301                 VectorNormalize(r_refdef.view.frustum[0].normal);
4302                 VectorNormalize(r_refdef.view.frustum[1].normal);
4303                 VectorNormalize(r_refdef.view.frustum[2].normal);
4304                 VectorNormalize(r_refdef.view.frustum[3].normal);
4305
4306                 // make the corners absolute
4307                 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4308                 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4309                 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4310                 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4311
4312                 // one more normal
4313                 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4314
4315                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4316                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4317                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4318                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4319                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4320         }
4321         else
4322         {
4323                 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4324                 VectorScale(left,  1.0f, r_refdef.view.frustum[1].normal);
4325                 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4326                 VectorScale(up,  1.0f, r_refdef.view.frustum[3].normal);
4327                 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4328                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4329                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4330                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4331                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4332                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4333         }
4334         r_refdef.view.numfrustumplanes = 5;
4335
4336         if (r_refdef.view.useclipplane)
4337         {
4338                 r_refdef.view.numfrustumplanes = 6;
4339                 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4340         }
4341
4342         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4343                 PlaneClassify(r_refdef.view.frustum + i);
4344
4345         // LadyHavoc: note to all quake engine coders, Quake had a special case
4346         // for 90 degrees which assumed a square view (wrong), so I removed it,
4347         // Quake2 has it disabled as well.
4348
4349         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4350         //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4351         //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4352         //PlaneClassify(&frustum[0]);
4353
4354         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4355         //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4356         //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4357         //PlaneClassify(&frustum[1]);
4358
4359         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4360         //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4361         //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4362         //PlaneClassify(&frustum[2]);
4363
4364         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4365         //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4366         //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4367         //PlaneClassify(&frustum[3]);
4368
4369         // nearclip plane
4370         //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4371         //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4372         //PlaneClassify(&frustum[4]);
4373 }
4374
4375 static void R_View_UpdateWithScissor(const int *myscissor)
4376 {
4377         R_Main_ResizeViewCache();
4378         R_View_SetFrustum(myscissor);
4379         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4380         R_View_UpdateEntityVisible();
4381 }
4382
4383 static void R_View_Update(void)
4384 {
4385         R_Main_ResizeViewCache();
4386         R_View_SetFrustum(NULL);
4387         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4388         R_View_UpdateEntityVisible();
4389 }
4390
4391 float viewscalefpsadjusted = 1.0f;
4392
4393 static void R_GetScaledViewSize(int width, int height, int *outwidth, int *outheight)
4394 {
4395         float scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
4396         scale = bound(0.03125f, scale, 1.0f);
4397         *outwidth = (int)ceil(width * scale);
4398         *outheight = (int)ceil(height * scale);
4399 }
4400
4401 void R_SetupView(qboolean allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4402 {
4403         const float *customclipplane = NULL;
4404         float plane[4];
4405         int /*rtwidth,*/ rtheight;
4406         if (r_refdef.view.useclipplane && allowwaterclippingplane)
4407         {
4408                 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4409                 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4410                 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4411                 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4412                         dist = r_refdef.view.clipplane.dist;
4413                 plane[0] = r_refdef.view.clipplane.normal[0];
4414                 plane[1] = r_refdef.view.clipplane.normal[1];
4415                 plane[2] = r_refdef.view.clipplane.normal[2];
4416                 plane[3] = -dist;
4417                 customclipplane = plane;
4418         }
4419
4420         //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
4421         rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
4422
4423         if (!r_refdef.view.useperspective)
4424                 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);
4425         else if (vid.stencil && r_useinfinitefarclip.integer)
4426                 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);
4427         else
4428                 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);
4429         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4430         R_SetViewport(&r_refdef.view.viewport);
4431 }
4432
4433 void R_EntityMatrix(const matrix4x4_t *matrix)
4434 {
4435         if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4436         {
4437                 gl_modelmatrixchanged = false;
4438                 gl_modelmatrix = *matrix;
4439                 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4440                 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4441                 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4442                 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4443                 CHECKGLERROR
4444                 switch(vid.renderpath)
4445                 {
4446                 case RENDERPATH_GL32:
4447                 case RENDERPATH_GLES2:
4448                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4449                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4450                         break;
4451                 }
4452         }
4453 }
4454
4455 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4456 {
4457         r_viewport_t viewport;
4458
4459         CHECKGLERROR
4460
4461         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
4462         R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4463         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4464         R_SetViewport(&viewport);
4465         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4466         GL_Color(1, 1, 1, 1);
4467         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4468         GL_BlendFunc(GL_ONE, GL_ZERO);
4469         GL_ScissorTest(false);
4470         GL_DepthMask(false);
4471         GL_DepthRange(0, 1);
4472         GL_DepthTest(false);
4473         GL_DepthFunc(GL_LEQUAL);
4474         R_EntityMatrix(&identitymatrix);
4475         R_Mesh_ResetTextureState();
4476         GL_PolygonOffset(0, 0);
4477         switch(vid.renderpath)
4478         {
4479         case RENDERPATH_GL32:
4480         case RENDERPATH_GLES2:
4481                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4482                 break;
4483         }
4484         GL_CullFace(GL_NONE);
4485
4486         CHECKGLERROR
4487 }
4488
4489 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4490 {
4491         R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4492 }
4493
4494 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4495 {
4496         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4497         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4498         GL_Color(1, 1, 1, 1);
4499         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4500         GL_BlendFunc(GL_ONE, GL_ZERO);
4501         GL_ScissorTest(true);
4502         GL_DepthMask(true);
4503         GL_DepthRange(0, 1);
4504         GL_DepthTest(true);
4505         GL_DepthFunc(GL_LEQUAL);
4506         R_EntityMatrix(&identitymatrix);
4507         R_Mesh_ResetTextureState();
4508         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4509         switch(vid.renderpath)
4510         {
4511         case RENDERPATH_GL32:
4512         case RENDERPATH_GLES2:
4513                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4514                 break;
4515         }
4516         GL_CullFace(r_refdef.view.cullface_back);
4517 }
4518
4519 /*
4520 ================
4521 R_RenderView_UpdateViewVectors
4522 ================
4523 */
4524 void R_RenderView_UpdateViewVectors(void)
4525 {
4526         // break apart the view matrix into vectors for various purposes
4527         // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4528         // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4529         Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4530         VectorNegate(r_refdef.view.left, r_refdef.view.right);
4531         // make an inverted copy of the view matrix for tracking sprites
4532         Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4533 }
4534
4535 void R_RenderTarget_FreeUnused(qboolean force)
4536 {
4537         unsigned int i, j, end;
4538         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4539         for (i = 0; i < end; i++)
4540         {
4541                 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4542                 // free resources for rendertargets that have not been used for a while
4543                 // (note: this check is run after the frame render, so any targets used
4544                 // this frame will not be affected even at low framerates)
4545                 if (r && (realtime - r->lastusetime > 0.2 || force))
4546                 {
4547                         if (r->fbo)
4548                                 R_Mesh_DestroyFramebufferObject(r->fbo);
4549                         for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4550                                 if (r->colortexture[j])
4551                                         R_FreeTexture(r->colortexture[j]);
4552                         if (r->depthtexture)
4553                                 R_FreeTexture(r->depthtexture);
4554                         Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4555                 }
4556         }
4557 }
4558
4559 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4560 {
4561         float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4562         x1 = x * iw;
4563         x2 = (x + w) * iw;
4564         y1 = (th - y) * ih;
4565         y2 = (th - y - h) * ih;
4566         texcoord2f[0] = x1;
4567         texcoord2f[2] = x2;
4568         texcoord2f[4] = x2;
4569         texcoord2f[6] = x1;
4570         texcoord2f[1] = y1;
4571         texcoord2f[3] = y1;
4572         texcoord2f[5] = y2;
4573         texcoord2f[7] = y2;
4574 }
4575
4576 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)
4577 {
4578         unsigned int i, j, end;
4579         r_rendertarget_t *r = NULL;
4580         char vabuf[256];
4581         // first try to reuse an existing slot if possible
4582         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4583         for (i = 0; i < end; i++)
4584         {
4585                 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4586                 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)
4587                         break;
4588         }
4589         if (i == end)
4590         {
4591                 // no unused exact match found, so we have to make one in the first unused slot
4592                 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4593                 r->texturewidth = texturewidth;
4594                 r->textureheight = textureheight;
4595                 r->colortextype[0] = colortextype0;
4596                 r->colortextype[1] = colortextype1;
4597                 r->colortextype[2] = colortextype2;
4598                 r->colortextype[3] = colortextype3;
4599                 r->depthtextype = depthtextype;
4600                 r->depthisrenderbuffer = depthisrenderbuffer;
4601                 for (j = 0; j < 4; j++)
4602                         if (r->colortextype[j])
4603                                 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);
4604                 if (r->depthtextype)
4605                 {
4606                         if (r->depthisrenderbuffer)
4607                                 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);
4608                         else
4609                                 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);
4610                 }
4611                 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4612         }
4613         r_refdef.stats[r_stat_rendertargets_used]++;
4614         r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4615         r->lastusetime = realtime;
4616         R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4617         return r;
4618 }
4619
4620 static void R_Water_StartFrame(void)
4621 {
4622         int waterwidth, waterheight;
4623
4624         if (vid.width > (int)vid.maxtexturesize_2d || vid.height > (int)vid.maxtexturesize_2d)
4625                 return;
4626
4627         // set waterwidth and waterheight to the water resolution that will be
4628         // used (often less than the screen resolution for faster rendering)
4629         waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width);
4630         waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height);
4631         R_GetScaledViewSize(waterwidth, waterheight, &waterwidth, &waterheight);
4632
4633         if (!r_water.integer || r_showsurfaces.integer)
4634                 waterwidth = waterheight = 0;
4635
4636         // set up variables that will be used in shader setup
4637         r_fb.water.waterwidth = waterwidth;
4638         r_fb.water.waterheight = waterheight;
4639         r_fb.water.texturewidth = waterwidth;
4640         r_fb.water.textureheight = waterheight;
4641         r_fb.water.camerawidth = waterwidth;
4642         r_fb.water.cameraheight = waterheight;
4643         r_fb.water.screenscale[0] = 0.5f;
4644         r_fb.water.screenscale[1] = 0.5f;
4645         r_fb.water.screencenter[0] = 0.5f;
4646         r_fb.water.screencenter[1] = 0.5f;
4647         r_fb.water.enabled = waterwidth != 0;
4648
4649         r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4650         r_fb.water.numwaterplanes = 0;
4651 }
4652
4653 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4654 {
4655         int planeindex, bestplaneindex, vertexindex;
4656         vec3_t mins, maxs, normal, center, v, n;
4657         vec_t planescore, bestplanescore;
4658         mplane_t plane;
4659         r_waterstate_waterplane_t *p;
4660         texture_t *t = R_GetCurrentTexture(surface->texture);
4661
4662         rsurface.texture = t;
4663         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4664         // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4665         if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4666                 return;
4667         // average the vertex normals, find the surface bounds (after deformvertexes)
4668         Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4669         Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4670         VectorCopy(n, normal);
4671         VectorCopy(v, mins);
4672         VectorCopy(v, maxs);
4673         for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4674         {
4675                 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4676                 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4677                 VectorAdd(normal, n, normal);
4678                 mins[0] = min(mins[0], v[0]);
4679                 mins[1] = min(mins[1], v[1]);
4680                 mins[2] = min(mins[2], v[2]);
4681                 maxs[0] = max(maxs[0], v[0]);
4682                 maxs[1] = max(maxs[1], v[1]);
4683                 maxs[2] = max(maxs[2], v[2]);
4684         }
4685         VectorNormalize(normal);
4686         VectorMAM(0.5f, mins, 0.5f, maxs, center);
4687
4688         VectorCopy(normal, plane.normal);
4689         VectorNormalize(plane.normal);
4690         plane.dist = DotProduct(center, plane.normal);
4691         PlaneClassify(&plane);
4692         if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4693         {
4694                 // skip backfaces (except if nocullface is set)
4695 //              if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4696 //                      return;
4697                 VectorNegate(plane.normal, plane.normal);
4698                 plane.dist *= -1;
4699                 PlaneClassify(&plane);
4700         }
4701
4702
4703         // find a matching plane if there is one
4704         bestplaneindex = -1;
4705         bestplanescore = 1048576.0f;
4706         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4707         {
4708                 if(p->camera_entity == t->camera_entity)
4709                 {
4710                         planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4711                         if (bestplaneindex < 0 || bestplanescore > planescore)
4712                         {
4713                                 bestplaneindex = planeindex;
4714                                 bestplanescore = planescore;
4715                         }
4716                 }
4717         }
4718         planeindex = bestplaneindex;
4719
4720         // if this surface does not fit any known plane rendered this frame, add one
4721         if (planeindex < 0 || bestplanescore > 0.001f)
4722         {
4723                 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4724                 {
4725                         // store the new plane
4726                         planeindex = r_fb.water.numwaterplanes++;
4727                         p = r_fb.water.waterplanes + planeindex;
4728                         p->plane = plane;
4729                         // clear materialflags and pvs
4730                         p->materialflags = 0;
4731                         p->pvsvalid = false;
4732                         p->camera_entity = t->camera_entity;
4733                         VectorCopy(mins, p->mins);
4734                         VectorCopy(maxs, p->maxs);
4735                 }
4736                 else
4737                 {
4738                         // We're totally screwed.
4739                         return;
4740                 }
4741         }
4742         else
4743         {
4744                 // merge mins/maxs when we're adding this surface to the plane
4745                 p = r_fb.water.waterplanes + planeindex;
4746                 p->mins[0] = min(p->mins[0], mins[0]);
4747                 p->mins[1] = min(p->mins[1], mins[1]);
4748                 p->mins[2] = min(p->mins[2], mins[2]);
4749                 p->maxs[0] = max(p->maxs[0], maxs[0]);
4750                 p->maxs[1] = max(p->maxs[1], maxs[1]);
4751                 p->maxs[2] = max(p->maxs[2], maxs[2]);
4752         }
4753         // merge this surface's materialflags into the waterplane
4754         p->materialflags |= t->currentmaterialflags;
4755         if(!(p->materialflags & MATERIALFLAG_CAMERA))
4756         {
4757                 // merge this surface's PVS into the waterplane
4758                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4759                  && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4760                 {
4761                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4762                         p->pvsvalid = true;
4763                 }
4764         }
4765 }
4766
4767 extern cvar_t r_drawparticles;
4768 extern cvar_t r_drawdecals;
4769
4770 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4771 {
4772         int myscissor[4];
4773         r_refdef_view_t originalview;
4774         r_refdef_view_t myview;
4775         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;
4776         r_waterstate_waterplane_t *p;
4777         vec3_t visorigin;
4778         r_rendertarget_t *rt;
4779
4780         originalview = r_refdef.view;
4781
4782         // lowquality hack, temporarily shut down some cvars and restore afterwards
4783         qualityreduction = r_water_lowquality.integer;
4784         if (qualityreduction > 0)
4785         {
4786                 if (qualityreduction >= 1)
4787                 {
4788                         old_r_shadows = r_shadows.integer;
4789                         old_r_worldrtlight = r_shadow_realtime_world.integer;
4790                         old_r_dlight = r_shadow_realtime_dlight.integer;
4791                         Cvar_SetValueQuick(&r_shadows, 0);
4792                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4793                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4794                 }
4795                 if (qualityreduction >= 2)
4796                 {
4797                         old_r_dynamic = r_dynamic.integer;
4798                         old_r_particles = r_drawparticles.integer;
4799                         old_r_decals = r_drawdecals.integer;
4800                         Cvar_SetValueQuick(&r_dynamic, 0);
4801                         Cvar_SetValueQuick(&r_drawparticles, 0);
4802                         Cvar_SetValueQuick(&r_drawdecals, 0);
4803                 }
4804         }
4805
4806         for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4807         {
4808                 p->rt_reflection = NULL;
4809                 p->rt_refraction = NULL;
4810                 p->rt_camera = NULL;
4811         }
4812
4813         // render views
4814         r_refdef.view = originalview;
4815         r_refdef.view.showdebug = false;
4816         r_refdef.view.width = r_fb.water.waterwidth;
4817         r_refdef.view.height = r_fb.water.waterheight;
4818         r_refdef.view.useclipplane = true;
4819         myview = r_refdef.view;
4820         r_fb.water.renderingscene = true;
4821         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4822         {
4823                 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4824                         continue;
4825
4826                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4827                 {
4828                         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);
4829                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4830                                 goto error;
4831                         r_refdef.view = myview;
4832                         Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4833                         Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4834                         if(r_water_scissormode.integer)
4835                         {
4836                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4837                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4838                                 {
4839                                         p->rt_reflection = NULL;
4840                                         p->rt_refraction = NULL;
4841                                         p->rt_camera = NULL;
4842                                         continue;
4843                                 }
4844                         }
4845
4846                         r_refdef.view.clipplane = p->plane;
4847                         // reflected view origin may be in solid, so don't cull with it
4848                         r_refdef.view.usevieworiginculling = false;
4849                         // reverse the cullface settings for this render
4850                         r_refdef.view.cullface_front = GL_FRONT;
4851                         r_refdef.view.cullface_back = GL_BACK;
4852                         // combined pvs (based on what can be seen from each surface center)
4853                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4854                         {
4855                                 r_refdef.view.usecustompvs = true;
4856                                 if (p->pvsvalid)
4857                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4858                                 else
4859                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4860                         }
4861
4862                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4863                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4864                         GL_ScissorTest(false);
4865                         R_ClearScreen(r_refdef.fogenabled);
4866                         GL_ScissorTest(true);
4867                         if(r_water_scissormode.integer & 2)
4868                                 R_View_UpdateWithScissor(myscissor);
4869                         else
4870                                 R_View_Update();
4871                         R_AnimCache_CacheVisibleEntities();
4872                         if(r_water_scissormode.integer & 1)
4873                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4874                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4875
4876                         r_fb.water.hideplayer = false;
4877                         p->rt_reflection = rt;
4878                 }
4879
4880                 // render the normal view scene and copy into texture
4881                 // (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)
4882                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
4883                 {
4884                         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);
4885                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4886                                 goto error;
4887                         r_refdef.view = myview;
4888                         if(r_water_scissormode.integer)
4889                         {
4890                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4891                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4892                                 {
4893                                         p->rt_reflection = NULL;
4894                                         p->rt_refraction = NULL;
4895                                         p->rt_camera = NULL;
4896                                         continue;
4897                                 }
4898                         }
4899
4900                         // combined pvs (based on what can be seen from each surface center)
4901                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4902                         {
4903                                 r_refdef.view.usecustompvs = true;
4904                                 if (p->pvsvalid)
4905                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4906                                 else
4907                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4908                         }
4909
4910                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
4911
4912                         r_refdef.view.clipplane = p->plane;
4913                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
4914                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
4915
4916                         if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
4917                         {
4918                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
4919                                 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
4920                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
4921                                 R_RenderView_UpdateViewVectors();
4922                                 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
4923                                 {
4924                                         r_refdef.view.usecustompvs = true;
4925                                         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);
4926                                 }
4927                         }
4928
4929                         PlaneClassify(&r_refdef.view.clipplane);
4930
4931                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4932                         GL_ScissorTest(false);
4933                         R_ClearScreen(r_refdef.fogenabled);
4934                         GL_ScissorTest(true);
4935                         if(r_water_scissormode.integer & 2)
4936                                 R_View_UpdateWithScissor(myscissor);
4937                         else
4938                                 R_View_Update();
4939                         R_AnimCache_CacheVisibleEntities();
4940                         if(r_water_scissormode.integer & 1)
4941                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4942                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4943
4944                         r_fb.water.hideplayer = false;
4945                         p->rt_refraction = rt;
4946                 }
4947                 else if (p->materialflags & MATERIALFLAG_CAMERA)
4948                 {
4949                         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);
4950                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4951                                 goto error;
4952                         r_refdef.view = myview;
4953
4954                         r_refdef.view.clipplane = p->plane;
4955                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
4956                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
4957
4958                         r_refdef.view.width = r_fb.water.camerawidth;
4959                         r_refdef.view.height = r_fb.water.cameraheight;
4960                         r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
4961                         r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
4962                         r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
4963                         r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
4964
4965                         if(p->camera_entity)
4966                         {
4967                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
4968                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
4969                         }
4970
4971                         // note: all of the view is used for displaying... so
4972                         // there is no use in scissoring
4973
4974                         // reverse the cullface settings for this render
4975                         r_refdef.view.cullface_front = GL_FRONT;
4976                         r_refdef.view.cullface_back = GL_BACK;
4977                         // also reverse the view matrix
4978                         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
4979                         R_RenderView_UpdateViewVectors();
4980                         if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
4981                         {
4982                                 r_refdef.view.usecustompvs = true;
4983                                 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);
4984                         }
4985                         
4986                         // camera needs no clipplane
4987                         r_refdef.view.useclipplane = false;
4988                         // TODO: is the camera origin always valid?  if so we don't need to clear this
4989                         r_refdef.view.usevieworiginculling = false;
4990
4991                         PlaneClassify(&r_refdef.view.clipplane);
4992
4993                         r_fb.water.hideplayer = false;
4994
4995                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4996                         GL_ScissorTest(false);
4997                         R_ClearScreen(r_refdef.fogenabled);
4998                         GL_ScissorTest(true);
4999                         R_View_Update();
5000                         R_AnimCache_CacheVisibleEntities();
5001                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5002
5003                         r_fb.water.hideplayer = false;
5004                         p->rt_camera = rt;
5005                 }
5006
5007         }
5008         r_fb.water.renderingscene = false;
5009         r_refdef.view = originalview;
5010         R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5011         R_View_Update();
5012         R_AnimCache_CacheVisibleEntities();
5013         goto finish;
5014 error:
5015         r_refdef.view = originalview;
5016         r_fb.water.renderingscene = false;
5017         Cvar_SetValueQuick(&r_water, 0);
5018         Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed!  Turned off r_water.\n");
5019 finish:
5020         // lowquality hack, restore cvars
5021         if (qualityreduction > 0)
5022         {
5023                 if (qualityreduction >= 1)
5024                 {
5025                         Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5026                         Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5027                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5028                 }
5029                 if (qualityreduction >= 2)
5030                 {
5031                         Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5032                         Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5033                         Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5034                 }
5035         }
5036 }
5037
5038 static void R_Bloom_StartFrame(void)
5039 {
5040         int screentexturewidth, screentextureheight;
5041         int viewwidth, viewheight;
5042         textype_t textype = TEXTYPE_COLORBUFFER;
5043
5044         // clear the pointers to rendertargets from last frame as they're stale
5045         r_fb.rt_screen = NULL;
5046         r_fb.rt_bloom = NULL;
5047
5048         switch (vid.renderpath)
5049         {
5050         case RENDERPATH_GL32:
5051                 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5052                 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5053                 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5054                 break;
5055         case RENDERPATH_GLES2:
5056                 r_fb.usedepthtextures = false;
5057                 break;
5058         }
5059
5060         if (r_viewscale_fpsscaling.integer)
5061         {
5062                 double actualframetime;
5063                 double targetframetime;
5064                 double adjust;
5065                 actualframetime = r_refdef.lastdrawscreentime;
5066                 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5067                 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5068                 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5069                 if (r_viewscale_fpsscaling_stepsize.value > 0)
5070                         adjust = (int)(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5071                 viewscalefpsadjusted += adjust;
5072                 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5073         }
5074         else
5075                 viewscalefpsadjusted = 1.0f;
5076
5077         R_GetScaledViewSize(r_refdef.view.width, r_refdef.view.height, &viewwidth, &viewheight);
5078
5079         // set bloomwidth and bloomheight to the bloom resolution that will be
5080         // used (often less than the screen resolution for faster rendering)
5081         r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, vid.width);
5082         r_fb.bloomheight = r_fb.bloomwidth * vid.height / vid.width;
5083         r_fb.bloomheight = bound(1, r_fb.bloomheight, vid.height);
5084         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5085         r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5086
5087         // calculate desired texture sizes
5088         screentexturewidth = viewwidth;
5089         screentextureheight = viewheight;
5090
5091         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))
5092         {
5093                 Cvar_SetValueQuick(&r_bloom, 0);
5094                 Cvar_SetValueQuick(&r_motionblur, 0);
5095                 Cvar_SetValueQuick(&r_damageblur, 0);
5096         }
5097
5098         // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5099         if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5100         {
5101                 if (r_fb.ghosttexture)
5102                         R_FreeTexture(r_fb.ghosttexture);
5103                 r_fb.ghosttexture = NULL;
5104
5105                 r_fb.screentexturewidth = screentexturewidth;
5106                 r_fb.screentextureheight = screentextureheight;
5107                 r_fb.textype = textype;
5108
5109                 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5110                 {
5111                         if (r_motionblur.value > 0 || r_damageblur.value > 0)
5112                                 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);
5113                         r_fb.ghosttexture_valid = false;
5114                 }
5115         }
5116
5117         if (r_bloom.integer)
5118         {
5119                 // bloom texture is a different resolution
5120                 r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.width);
5121                 r_fb.bloomheight = r_fb.bloomwidth * r_refdef.view.height / r_refdef.view.width;
5122                 r_fb.bloomheight = bound(1, r_fb.bloomheight, r_refdef.view.height);
5123         }
5124         else
5125                 r_fb.bloomwidth = r_fb.bloomheight = 0;
5126
5127         r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5128
5129         r_refdef.view.clear = true;
5130 }
5131
5132 static void R_Bloom_MakeTexture(void)
5133 {
5134         int x, range, dir;
5135         float xoffset, yoffset, r, brighten;
5136         float colorscale = r_bloom_colorscale.value;
5137         r_viewport_t bloomviewport;
5138         r_rendertarget_t *prev, *cur;
5139         textype_t textype = r_fb.rt_screen->colortextype[0];
5140
5141         r_refdef.stats[r_stat_bloom]++;
5142
5143         R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5144
5145         // scale down screen texture to the bloom texture size
5146         CHECKGLERROR
5147         prev = r_fb.rt_screen;
5148         cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5149         R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5150         R_SetViewport(&bloomviewport);
5151         GL_CullFace(GL_NONE);
5152         GL_DepthTest(false);
5153         GL_BlendFunc(GL_ONE, GL_ZERO);
5154         GL_Color(colorscale, colorscale, colorscale, 1);
5155         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5156         // TODO: do boxfilter scale-down in shader?
5157         R_SetupShader_Generic(prev->colortexture[0], false, true, true);
5158         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5159         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5160         // we now have a properly scaled bloom image
5161
5162         // multiply bloom image by itself as many times as desired to darken it
5163         // TODO: if people actually use this it could be done more quickly in the previous shader pass
5164         for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5165         {
5166                 prev = cur;
5167                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5168                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5169                 x *= 2;
5170                 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5171                 if(x <= 2)
5172                         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0);
5173                 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5174                 GL_Color(1,1,1,1); // no fix factor supported here
5175                 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5176                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5177                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5178                 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5179         }
5180         CHECKGLERROR
5181
5182         range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5183         brighten = r_bloom_brighten.value;
5184         brighten = sqrt(brighten);
5185         if(range >= 1)
5186                 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5187
5188         for (dir = 0;dir < 2;dir++)
5189         {
5190                 prev = cur;
5191                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5192                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5193                 // blend on at multiple vertical offsets to achieve a vertical blur
5194                 // TODO: do offset blends using GLSL
5195                 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5196                 CHECKGLERROR
5197                 GL_BlendFunc(GL_ONE, GL_ZERO);
5198                 CHECKGLERROR
5199                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5200                 CHECKGLERROR
5201                 for (x = -range;x <= range;x++)
5202                 {
5203                         if (!dir){xoffset = 0;yoffset = x;}
5204                         else {xoffset = x;yoffset = 0;}
5205                         xoffset /= (float)prev->texturewidth;
5206                         yoffset /= (float)prev->textureheight;
5207                         // compute a texcoord array with the specified x and y offset
5208                         r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5209                         r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5210                         r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5211                         r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5212                         r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5213                         r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5214                         r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5215                         r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5216                         // this r value looks like a 'dot' particle, fading sharply to
5217                         // black at the edges
5218                         // (probably not realistic but looks good enough)
5219                         //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5220                         //r = brighten/(range*2+1);
5221                         r = brighten / (range * 2 + 1);
5222                         if(range >= 1)
5223                                 r *= (1 - x*x/(float)((range+1)*(range+1)));
5224                         if (r <= 0)
5225                                 continue;
5226                         CHECKGLERROR
5227                         GL_Color(r, r, r, 1);
5228                         CHECKGLERROR
5229                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5230                         CHECKGLERROR
5231                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5232                         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5233                         CHECKGLERROR
5234                         GL_BlendFunc(GL_ONE, GL_ONE);
5235                         CHECKGLERROR
5236                 }
5237         }
5238
5239         // now we have the bloom image, so keep track of it
5240         r_fb.rt_bloom = cur;
5241 }
5242
5243 static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5244 {
5245         dpuint64 permutation;
5246         float uservecs[4][4];
5247         rtexture_t *viewtexture;
5248         rtexture_t *bloomtexture;
5249
5250         R_EntityMatrix(&identitymatrix);
5251
5252         if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
5253         {
5254                 // declare variables
5255                 float blur_factor, blur_mouseaccel, blur_velocity;
5256                 static float blur_average; 
5257                 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5258
5259                 // set a goal for the factoring
5260                 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value) 
5261                         / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5262                 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value) 
5263                         / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5264                 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value) 
5265                         + (blur_mouseaccel * r_motionblur_mousefactor.value));
5266
5267                 // from the goal, pick an averaged value between goal and last value
5268                 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5269                 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5270
5271                 // enforce minimum amount of blur 
5272                 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5273
5274                 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5275
5276                 // calculate values into a standard alpha
5277                 cl.motionbluralpha = 1 - exp(-
5278                                 (
5279                                         (r_motionblur.value * blur_factor / 80)
5280                                         +
5281                                         (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5282                                 )
5283                                 /
5284                                 max(0.0001, cl.time - cl.oldtime) // fps independent
5285                                 );
5286
5287                 // randomization for the blur value to combat persistent ghosting
5288                 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5289                 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5290
5291                 // apply the blur
5292                 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5293                 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5294                 {
5295                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5296                         GL_Color(1, 1, 1, cl.motionbluralpha);
5297                         R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5298                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5299                         R_SetupShader_Generic(r_fb.ghosttexture, false, true, true);
5300                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5301                         r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5302                 }
5303
5304                 // updates old view angles for next pass
5305                 VectorCopy(cl.viewangles, blur_oldangles);
5306
5307                 // copy view into the ghost texture
5308                 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5309                 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5310                 r_fb.ghosttexture_valid = true;
5311         }
5312
5313         if (r_fb.bloomwidth)
5314         {
5315                 // make the bloom texture
5316                 R_Bloom_MakeTexture();
5317         }
5318
5319 #if _MSC_VER >= 1400
5320 #define sscanf sscanf_s
5321 #endif
5322         memset(uservecs, 0, sizeof(uservecs));
5323         if (r_glsl_postprocess_uservec1_enable.integer)
5324                 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5325         if (r_glsl_postprocess_uservec2_enable.integer)
5326                 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5327         if (r_glsl_postprocess_uservec3_enable.integer)
5328                 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5329         if (r_glsl_postprocess_uservec4_enable.integer)
5330                 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5331
5332         // render to the screen fbo
5333         R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5334         GL_Color(1, 1, 1, 1);
5335         GL_BlendFunc(GL_ONE, GL_ZERO);
5336
5337         viewtexture = r_fb.rt_screen->colortexture[0];
5338         bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5339
5340         if (r_rendertarget_debug.integer >= 0)
5341         {
5342                 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5343                 if (rt && rt->colortexture[0])
5344                 {
5345                         viewtexture = rt->colortexture[0];
5346                         bloomtexture = NULL;
5347                 }
5348         }
5349
5350         R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5351         switch(vid.renderpath)
5352         {
5353         case RENDERPATH_GL32:
5354         case RENDERPATH_GLES2:
5355                 permutation =
5356                         (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5357                         | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5358                         | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5359                         | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5360                         | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5361                 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5362                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First     , viewtexture);
5363                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second    , bloomtexture);
5364                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps       );
5365                 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]);
5366                 if (r_glsl_permutation->loc_PixelSize               >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize         , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5367                 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]);
5368                 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]);
5369                 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]);
5370                 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]);
5371                 if (r_glsl_permutation->loc_Saturation              >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation        , r_glsl_saturation.value);
5372                 if (r_glsl_permutation->loc_PixelToScreenTexCoord   >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
5373                 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);
5374                 if (r_glsl_permutation->loc_ColorFringe             >= 0) qglUniform1f(r_glsl_permutation->loc_ColorFringe, r_colorfringe.value );
5375                 break;
5376         }
5377         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5378         r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5379 }
5380
5381 matrix4x4_t r_waterscrollmatrix;
5382
5383 void R_UpdateFog(void)
5384 {
5385         // Nehahra fog
5386         if (gamemode == GAME_NEHAHRA)
5387         {
5388                 if (gl_fogenable.integer)
5389                 {
5390                         r_refdef.oldgl_fogenable = true;
5391                         r_refdef.fog_density = gl_fogdensity.value;
5392                         r_refdef.fog_red = gl_fogred.value;
5393                         r_refdef.fog_green = gl_foggreen.value;
5394                         r_refdef.fog_blue = gl_fogblue.value;
5395                         r_refdef.fog_alpha = 1;
5396                         r_refdef.fog_start = 0;
5397                         r_refdef.fog_end = gl_skyclip.value;
5398                         r_refdef.fog_height = 1<<30;
5399                         r_refdef.fog_fadedepth = 128;
5400                 }
5401                 else if (r_refdef.oldgl_fogenable)
5402                 {
5403                         r_refdef.oldgl_fogenable = false;
5404                         r_refdef.fog_density = 0;
5405                         r_refdef.fog_red = 0;
5406                         r_refdef.fog_green = 0;
5407                         r_refdef.fog_blue = 0;
5408                         r_refdef.fog_alpha = 0;
5409                         r_refdef.fog_start = 0;
5410                         r_refdef.fog_end = 0;
5411                         r_refdef.fog_height = 1<<30;
5412                         r_refdef.fog_fadedepth = 128;
5413                 }
5414         }
5415
5416         // fog parms
5417         r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5418         r_refdef.fog_start = max(0, r_refdef.fog_start);
5419         r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5420
5421         if (r_refdef.fog_density && r_drawfog.integer)
5422         {
5423                 r_refdef.fogenabled = true;
5424                 // this is the point where the fog reaches 0.9986 alpha, which we
5425                 // consider a good enough cutoff point for the texture
5426                 // (0.9986 * 256 == 255.6)
5427                 if (r_fog_exp2.integer)
5428                         r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5429                 else
5430                         r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5431                 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5432                 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5433                 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5434                 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5435                         R_BuildFogHeightTexture();
5436                 // fog color was already set
5437                 // update the fog texture
5438                 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)
5439                         R_BuildFogTexture();
5440                 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5441                 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5442         }
5443         else
5444                 r_refdef.fogenabled = false;
5445
5446         // fog color
5447         if (r_refdef.fog_density)
5448         {
5449                 r_refdef.fogcolor[0] = r_refdef.fog_red;
5450                 r_refdef.fogcolor[1] = r_refdef.fog_green;
5451                 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5452
5453                 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5454                 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5455                 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5456                 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5457
5458                 {
5459                         vec3_t fogvec;
5460                         VectorCopy(r_refdef.fogcolor, fogvec);
5461                         //   color.rgb *= ContrastBoost * SceneBrightness;
5462                         VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5463                         r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5464                         r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5465                         r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5466                 }
5467         }
5468 }
5469
5470 void R_UpdateVariables(void)
5471 {
5472         R_Textures_Frame();
5473
5474         r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5475
5476         r_refdef.farclip = r_farclip_base.value;
5477         if (r_refdef.scene.worldmodel)
5478                 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5479         r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5480
5481         if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5482                 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5483         r_refdef.polygonfactor = 0;
5484         r_refdef.polygonoffset = 0;
5485
5486         r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5487         r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5488         r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5489         r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5490         r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5491         if (r_refdef.scene.worldmodel)
5492         {
5493                 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5494         }
5495         if (r_showsurfaces.integer)
5496         {
5497                 r_refdef.scene.rtworld = false;
5498                 r_refdef.scene.rtworldshadows = false;
5499                 r_refdef.scene.rtdlight = false;
5500                 r_refdef.scene.rtdlightshadows = false;
5501                 r_refdef.scene.lightmapintensity = 0;
5502         }
5503
5504         r_gpuskeletal = false;
5505         switch(vid.renderpath)
5506         {
5507         case RENDERPATH_GL32:
5508                 r_gpuskeletal = r_glsl_skeletal.integer && !r_showsurfaces.integer;
5509         case RENDERPATH_GLES2:
5510                 if(!vid_gammatables_trivial)
5511                 {
5512                         if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5513                         {
5514                                 // build GLSL gamma texture
5515 #define RAMPWIDTH 256
5516                                 unsigned short ramp[RAMPWIDTH * 3];
5517                                 unsigned char rampbgr[RAMPWIDTH][4];
5518                                 int i;
5519
5520                                 r_texture_gammaramps_serial = vid_gammatables_serial;
5521
5522                                 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5523                                 for(i = 0; i < RAMPWIDTH; ++i)
5524                                 {
5525                                         rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5526                                         rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5527                                         rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5528                                         rampbgr[i][3] = 0;
5529                                 }
5530                                 if (r_texture_gammaramps)
5531                                 {
5532                                         R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1);
5533                                 }
5534                                 else
5535                                 {
5536                                         r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5537                                 }
5538                         }
5539                 }
5540                 else
5541                 {
5542                         // remove GLSL gamma texture
5543                 }
5544                 break;
5545         }
5546 }
5547
5548 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5549 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5550 /*
5551 ================
5552 R_SelectScene
5553 ================
5554 */
5555 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5556         if( scenetype != r_currentscenetype ) {
5557                 // store the old scenetype
5558                 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5559                 r_currentscenetype = scenetype;
5560                 // move in the new scene
5561                 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5562         }
5563 }
5564
5565 /*
5566 ================
5567 R_GetScenePointer
5568 ================
5569 */
5570 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5571 {
5572         // of course, we could also add a qboolean that provides a lock state and a ReleaseScenePointer function..
5573         if( scenetype == r_currentscenetype ) {
5574                 return &r_refdef.scene;
5575         } else {
5576                 return &r_scenes_store[ scenetype ];
5577         }
5578 }
5579
5580 static int R_SortEntities_Compare(const void *ap, const void *bp)
5581 {
5582         const entity_render_t *a = *(const entity_render_t **)ap;
5583         const entity_render_t *b = *(const entity_render_t **)bp;
5584
5585         // 1. compare model
5586         if(a->model < b->model)
5587                 return -1;
5588         if(a->model > b->model)
5589                 return +1;
5590
5591         // 2. compare skin
5592         // TODO possibly calculate the REAL skinnum here first using
5593         // skinscenes?
5594         if(a->skinnum < b->skinnum)
5595                 return -1;
5596         if(a->skinnum > b->skinnum)
5597                 return +1;
5598
5599         // everything we compared is equal
5600         return 0;
5601 }
5602 static void R_SortEntities(void)
5603 {
5604         // below or equal 2 ents, sorting never gains anything
5605         if(r_refdef.scene.numentities <= 2)
5606                 return;
5607         // sort
5608         qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5609 }
5610
5611 /*
5612 ================
5613 R_RenderView
5614 ================
5615 */
5616 extern cvar_t r_shadow_bouncegrid;
5617 extern cvar_t v_isometric;
5618 extern void V_MakeViewIsometric(void);
5619 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5620 {
5621         matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5622         int viewfbo = 0;
5623         rtexture_t *viewdepthtexture = NULL;
5624         rtexture_t *viewcolortexture = NULL;
5625         int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5626
5627         // finish any 2D rendering that was queued
5628         DrawQ_Finish();
5629
5630         if (r_timereport_active)
5631                 R_TimeReport("start");
5632         r_textureframe++; // used only by R_GetCurrentTexture
5633         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5634
5635         if(R_CompileShader_CheckStaticParms())
5636                 R_GLSL_Restart_f(&cmd_client);
5637
5638         if (!r_drawentities.integer)
5639                 r_refdef.scene.numentities = 0;
5640         else if (r_sortentities.integer)
5641                 R_SortEntities();
5642
5643         R_AnimCache_ClearCache();
5644
5645         /* adjust for stereo display */
5646         if(R_Stereo_Active())
5647         {
5648                 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);
5649                 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5650         }
5651
5652         if (r_refdef.view.isoverlay)
5653         {
5654                 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5655                 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5656                 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5657                 R_TimeReport("depthclear");
5658
5659                 r_refdef.view.showdebug = false;
5660
5661                 r_fb.water.enabled = false;
5662                 r_fb.water.numwaterplanes = 0;
5663
5664                 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5665
5666                 r_refdef.view.matrix = originalmatrix;
5667
5668                 CHECKGLERROR
5669                 return;
5670         }
5671
5672         if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5673         {
5674                 r_refdef.view.matrix = originalmatrix;
5675                 return;
5676         }
5677
5678         r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5679         if (v_isometric.integer && r_refdef.view.ismain)
5680                 V_MakeViewIsometric();
5681
5682         r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5683
5684         if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5685                 // in sRGB fallback, behave similar to true sRGB: convert this
5686                 // value from linear to sRGB
5687                 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5688
5689         R_RenderView_UpdateViewVectors();
5690
5691         R_Shadow_UpdateWorldLightSelection();
5692
5693         // this will set up r_fb.rt_screen
5694         R_Bloom_StartFrame();
5695
5696         // apply bloom brightness offset
5697         if(r_fb.rt_bloom)
5698                 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5699
5700         // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5701         if (r_fb.rt_screen)
5702         {
5703                 viewfbo = r_fb.rt_screen->fbo;
5704                 viewdepthtexture = r_fb.rt_screen->depthtexture;
5705                 viewcolortexture = r_fb.rt_screen->colortexture[0];
5706                 viewx = 0;
5707                 viewy = 0;
5708                 viewwidth = width;
5709                 viewheight = height;
5710         }
5711
5712         R_Water_StartFrame();
5713
5714         CHECKGLERROR
5715         if (r_timereport_active)
5716                 R_TimeReport("viewsetup");
5717
5718         R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5719
5720         // clear the whole fbo every frame - otherwise the driver will consider
5721         // it to be an inter-frame texture and stall in multi-gpu configurations
5722         if (r_fb.rt_screen)
5723                 GL_ScissorTest(false);
5724         R_ClearScreen(r_refdef.fogenabled);
5725         if (r_timereport_active)
5726                 R_TimeReport("viewclear");
5727
5728         r_refdef.view.clear = true;
5729
5730         r_refdef.view.showdebug = true;
5731
5732         R_View_Update();
5733         if (r_timereport_active)
5734                 R_TimeReport("visibility");
5735
5736         R_AnimCache_CacheVisibleEntities();
5737         if (r_timereport_active)
5738                 R_TimeReport("animcache");
5739
5740         R_Shadow_UpdateBounceGridTexture();
5741         // R_Shadow_UpdateBounceGridTexture called R_TimeReport a few times internally, so we don't need to do that here.
5742
5743         r_fb.water.numwaterplanes = 0;
5744         if (r_fb.water.enabled)
5745                 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5746
5747         // for the actual view render we use scissoring a fair amount, so scissor
5748         // test needs to be on
5749         if (r_fb.rt_screen)
5750                 GL_ScissorTest(true);
5751         GL_Scissor(viewx, viewy, viewwidth, viewheight);
5752         R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5753         r_fb.water.numwaterplanes = 0;
5754
5755         // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5756         GL_ScissorTest(false);
5757
5758         R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
5759         if (r_timereport_active)
5760                 R_TimeReport("blendview");
5761
5762         r_refdef.view.matrix = originalmatrix;
5763
5764         CHECKGLERROR
5765
5766         // go back to 2d rendering
5767         DrawQ_Start();
5768 }
5769
5770 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5771 {
5772         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5773         {
5774                 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5775                 if (r_timereport_active)
5776                         R_TimeReport("waterworld");
5777         }
5778
5779         // don't let sound skip if going slow
5780         if (r_refdef.scene.extraupdate)
5781                 S_ExtraUpdate ();
5782
5783         R_DrawModelsAddWaterPlanes();
5784         if (r_timereport_active)
5785                 R_TimeReport("watermodels");
5786
5787         if (r_fb.water.numwaterplanes)
5788         {
5789                 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5790                 if (r_timereport_active)
5791                         R_TimeReport("waterscenes");
5792         }
5793 }
5794
5795 extern cvar_t cl_locs_show;
5796 static void R_DrawLocs(void);
5797 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5798 static void R_DrawModelDecals(void);
5799 extern qboolean r_shadow_usingdeferredprepass;
5800 extern int r_shadow_shadowmapatlas_modelshadows_size;
5801 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5802 {
5803         qboolean shadowmapping = false;
5804
5805         if (r_timereport_active)
5806                 R_TimeReport("beginscene");
5807
5808         r_refdef.stats[r_stat_renders]++;
5809
5810         R_UpdateFog();
5811
5812         // don't let sound skip if going slow
5813         if (r_refdef.scene.extraupdate)
5814                 S_ExtraUpdate ();
5815
5816         R_MeshQueue_BeginScene();
5817
5818         R_SkyStartFrame();
5819
5820         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);
5821
5822         if (r_timereport_active)
5823                 R_TimeReport("skystartframe");
5824
5825         if (cl.csqc_vidvars.drawworld)
5826         {
5827                 // don't let sound skip if going slow
5828                 if (r_refdef.scene.extraupdate)
5829                         S_ExtraUpdate ();
5830
5831                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5832                 {
5833                         r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5834                         if (r_timereport_active)
5835                                 R_TimeReport("worldsky");
5836                 }
5837
5838                 if (R_DrawBrushModelsSky() && r_timereport_active)
5839                         R_TimeReport("bmodelsky");
5840
5841                 if (skyrendermasked && skyrenderlater)
5842                 {
5843                         // we have to force off the water clipping plane while rendering sky
5844                         R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5845                         R_Sky();
5846                         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5847                         if (r_timereport_active)
5848                                 R_TimeReport("sky");
5849                 }
5850         }
5851
5852         // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5853         r_shadow_viewfbo = viewfbo;
5854         r_shadow_viewdepthtexture = viewdepthtexture;
5855         r_shadow_viewcolortexture = viewcolortexture;
5856         r_shadow_viewx = viewx;
5857         r_shadow_viewy = viewy;
5858         r_shadow_viewwidth = viewwidth;
5859         r_shadow_viewheight = viewheight;
5860
5861         R_Shadow_PrepareModelShadows();
5862         R_Shadow_PrepareLights();
5863         if (r_timereport_active)
5864                 R_TimeReport("preparelights");
5865
5866         // render all the shadowmaps that will be used for this view
5867         shadowmapping = R_Shadow_ShadowMappingEnabled();
5868         if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
5869         {
5870                 R_Shadow_DrawShadowMaps();
5871                 if (r_timereport_active)
5872                         R_TimeReport("shadowmaps");
5873         }
5874
5875         // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
5876         if (r_shadow_usingdeferredprepass)
5877                 R_Shadow_DrawPrepass();
5878
5879         // now we begin the forward pass of the view render
5880         if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
5881         {
5882                 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
5883                 if (r_timereport_active)
5884                         R_TimeReport("worlddepth");
5885         }
5886         if (r_depthfirst.integer >= 2)
5887         {
5888                 R_DrawModelsDepth();
5889                 if (r_timereport_active)
5890                         R_TimeReport("modeldepth");
5891         }
5892
5893         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
5894         {
5895                 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
5896                 if (r_timereport_active)
5897                         R_TimeReport("world");
5898         }
5899
5900         // don't let sound skip if going slow
5901         if (r_refdef.scene.extraupdate)
5902                 S_ExtraUpdate ();
5903
5904         R_DrawModels();
5905         if (r_timereport_active)
5906                 R_TimeReport("models");
5907
5908         // don't let sound skip if going slow
5909         if (r_refdef.scene.extraupdate)
5910                 S_ExtraUpdate ();
5911
5912         if (!r_shadow_usingdeferredprepass)
5913         {
5914                 R_Shadow_DrawLights();
5915                 if (r_timereport_active)
5916                         R_TimeReport("rtlights");
5917         }
5918
5919         // don't let sound skip if going slow
5920         if (r_refdef.scene.extraupdate)
5921                 S_ExtraUpdate ();
5922
5923         if (cl.csqc_vidvars.drawworld)
5924         {
5925                 R_DrawModelDecals();
5926                 if (r_timereport_active)
5927                         R_TimeReport("modeldecals");
5928
5929                 R_DrawParticles();
5930                 if (r_timereport_active)
5931                         R_TimeReport("particles");
5932
5933                 R_DrawExplosions();
5934                 if (r_timereport_active)
5935                         R_TimeReport("explosions");
5936         }
5937
5938         if (r_refdef.view.showdebug)
5939         {
5940                 if (cl_locs_show.integer)
5941                 {
5942                         R_DrawLocs();
5943                         if (r_timereport_active)
5944                                 R_TimeReport("showlocs");
5945                 }
5946
5947                 if (r_drawportals.integer)
5948                 {
5949                         R_DrawPortals();
5950                         if (r_timereport_active)
5951                                 R_TimeReport("portals");
5952                 }
5953
5954                 if (r_showbboxes_client.value > 0)
5955                 {
5956                         R_DrawEntityBBoxes(CLVM_prog);
5957                         if (r_timereport_active)
5958                                 R_TimeReport("clbboxes");
5959                 }
5960                 if (r_showbboxes.value > 0)
5961                 {
5962                         R_DrawEntityBBoxes(SVVM_prog);
5963                         if (r_timereport_active)
5964                                 R_TimeReport("svbboxes");
5965                 }
5966         }
5967
5968         if (r_transparent.integer)
5969         {
5970                 R_MeshQueue_RenderTransparent();
5971                 if (r_timereport_active)
5972                         R_TimeReport("drawtrans");
5973         }
5974
5975         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))
5976         {
5977                 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
5978                 if (r_timereport_active)
5979                         R_TimeReport("worlddebug");
5980                 R_DrawModelsDebug();
5981                 if (r_timereport_active)
5982                         R_TimeReport("modeldebug");
5983         }
5984
5985         if (cl.csqc_vidvars.drawworld)
5986         {
5987                 R_Shadow_DrawCoronas();
5988                 if (r_timereport_active)
5989                         R_TimeReport("coronas");
5990         }
5991
5992         // don't let sound skip if going slow
5993         if (r_refdef.scene.extraupdate)
5994                 S_ExtraUpdate ();
5995 }
5996
5997 static const unsigned short bboxelements[36] =
5998 {
5999         5, 1, 3, 5, 3, 7,
6000         6, 2, 0, 6, 0, 4,
6001         7, 3, 2, 7, 2, 6,
6002         4, 0, 1, 4, 1, 5,
6003         4, 5, 7, 4, 7, 6,
6004         1, 0, 2, 1, 2, 3,
6005 };
6006
6007 #define BBOXEDGES 13
6008 static const float bboxedges[BBOXEDGES][6] = 
6009 {
6010         // whole box
6011         { 0, 0, 0, 1, 1, 1 },
6012         // bottom edges
6013         { 0, 0, 0, 0, 1, 0 },
6014         { 0, 0, 0, 1, 0, 0 },
6015         { 0, 1, 0, 1, 1, 0 },
6016         { 1, 0, 0, 1, 1, 0 },
6017         // top edges
6018         { 0, 0, 1, 0, 1, 1 },
6019         { 0, 0, 1, 1, 0, 1 },
6020         { 0, 1, 1, 1, 1, 1 },
6021         { 1, 0, 1, 1, 1, 1 },
6022         // vertical edges
6023         { 0, 0, 0, 0, 0, 1 },
6024         { 1, 0, 0, 1, 0, 1 },
6025         { 0, 1, 0, 0, 1, 1 },
6026         { 1, 1, 0, 1, 1, 1 },
6027 };
6028
6029 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6030 {
6031         int numvertices = BBOXEDGES * 8;
6032         float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6033         int numtriangles = BBOXEDGES * 12;
6034         unsigned short elements[BBOXEDGES * 36];
6035         int i, edge;
6036         float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6037
6038         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6039
6040         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6041         GL_DepthMask(false);
6042         GL_DepthRange(0, 1);
6043         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6044
6045         for (edge = 0; edge < BBOXEDGES; edge++)
6046         {
6047                 for (i = 0; i < 3; i++)
6048                 {
6049                         edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6050                         edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6051                 }
6052                 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6053                 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6054                 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6055                 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6056                 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6057                 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6058                 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6059                 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6060                 for (i = 0; i < 36; i++)
6061                         elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6062         }
6063         R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6064         if (r_refdef.fogenabled)
6065         {
6066                 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6067                 {
6068                         f1 = RSurf_FogVertex(v);
6069                         f2 = 1 - f1;
6070                         c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6071                         c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6072                         c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6073                 }
6074         }
6075         R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6076         R_Mesh_ResetTextureState();
6077         R_SetupShader_Generic_NoTexture(false, false);
6078         R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6079 }
6080
6081 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6082 {
6083         // hacky overloading of the parameters
6084         prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6085         int i;
6086         float color[4];
6087         prvm_edict_t *edict;
6088
6089         GL_CullFace(GL_NONE);
6090         R_SetupShader_Generic_NoTexture(false, false);
6091
6092         for (i = 0;i < numsurfaces;i++)
6093         {
6094                 edict = PRVM_EDICT_NUM(surfacelist[i]);
6095                 switch ((int)PRVM_serveredictfloat(edict, solid))
6096                 {
6097                         case SOLID_NOT:      Vector4Set(color, 1, 1, 1, 0.05);break;
6098                         case SOLID_TRIGGER:  Vector4Set(color, 1, 0, 1, 0.10);break;
6099                         case SOLID_BBOX:     Vector4Set(color, 0, 1, 0, 0.10);break;
6100                         case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6101                         case SOLID_BSP:      Vector4Set(color, 0, 0, 1, 0.05);break;
6102                         case SOLID_CORPSE:   Vector4Set(color, 1, 0.5, 0, 0.05);break;
6103                         default:             Vector4Set(color, 0, 0, 0, 0.50);break;
6104                 }
6105                 if (prog == CLVM_prog)
6106                         color[3] *= r_showbboxes_client.value;
6107                 else
6108                         color[3] *= r_showbboxes.value;
6109                 color[3] = bound(0, color[3], 1);
6110                 GL_DepthTest(!r_showdisabledepthtest.integer);
6111                 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6112         }
6113 }
6114
6115 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6116 {
6117         int i;
6118         prvm_edict_t *edict;
6119         vec3_t center;
6120
6121         if (prog == NULL)
6122                 return;
6123
6124         for (i = 0; i < prog->num_edicts; i++)
6125         {
6126                 edict = PRVM_EDICT_NUM(i);
6127                 if (edict->priv.server->free)
6128                         continue;
6129                 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6130                 if (PRVM_gameedictedict(edict, tag_entity) != 0)
6131                         continue;
6132                 if (prog == SVVM_prog && PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6133                         continue;
6134                 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6135                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6136         }
6137 }
6138
6139 static const int nomodelelement3i[24] =
6140 {
6141         5, 2, 0,
6142         5, 1, 2,
6143         5, 0, 3,
6144         5, 3, 1,
6145         0, 2, 4,
6146         2, 1, 4,
6147         3, 0, 4,
6148         1, 3, 4
6149 };
6150
6151 static const unsigned short nomodelelement3s[24] =
6152 {
6153         5, 2, 0,
6154         5, 1, 2,
6155         5, 0, 3,
6156         5, 3, 1,
6157         0, 2, 4,
6158         2, 1, 4,
6159         3, 0, 4,
6160         1, 3, 4
6161 };
6162
6163 static const float nomodelvertex3f[6*3] =
6164 {
6165         -16,   0,   0,
6166          16,   0,   0,
6167           0, -16,   0,
6168           0,  16,   0,
6169           0,   0, -16,
6170           0,   0,  16
6171 };
6172
6173 static const float nomodelcolor4f[6*4] =
6174 {
6175         0.0f, 0.0f, 0.5f, 1.0f,
6176         0.0f, 0.0f, 0.5f, 1.0f,
6177         0.0f, 0.5f, 0.0f, 1.0f,
6178         0.0f, 0.5f, 0.0f, 1.0f,
6179         0.5f, 0.0f, 0.0f, 1.0f,
6180         0.5f, 0.0f, 0.0f, 1.0f
6181 };
6182
6183 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6184 {
6185         int i;
6186         float f1, f2, *c;
6187         float color4f[6*4];
6188
6189         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);
6190
6191         // this is only called once per entity so numsurfaces is always 1, and
6192         // surfacelist is always {0}, so this code does not handle batches
6193
6194         if (rsurface.ent_flags & RENDER_ADDITIVE)
6195         {
6196                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6197                 GL_DepthMask(false);
6198         }
6199         else if (ent->alpha < 1)
6200         {
6201                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6202                 GL_DepthMask(false);
6203         }
6204         else
6205         {
6206                 GL_BlendFunc(GL_ONE, GL_ZERO);
6207                 GL_DepthMask(true);
6208         }
6209         GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6210         GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6211         GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6212         GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6213         memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6214         for (i = 0, c = color4f;i < 6;i++, c += 4)
6215         {
6216                 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6217                 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6218                 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6219                 c[3] *= ent->alpha;
6220         }
6221         if (r_refdef.fogenabled)
6222         {
6223                 for (i = 0, c = color4f;i < 6;i++, c += 4)
6224                 {
6225                         f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6226                         f2 = 1 - f1;
6227                         c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6228                         c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6229                         c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6230                 }
6231         }
6232 //      R_Mesh_ResetTextureState();
6233         R_SetupShader_Generic_NoTexture(false, false);
6234         R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6235         R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6236 }
6237
6238 void R_DrawNoModel(entity_render_t *ent)
6239 {
6240         vec3_t org;
6241         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6242         if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6243                 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6244         else
6245                 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6246 }
6247
6248 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6249 {
6250         vec3_t right1, right2, diff, normal;
6251
6252         VectorSubtract (org2, org1, normal);
6253
6254         // calculate 'right' vector for start
6255         VectorSubtract (r_refdef.view.origin, org1, diff);
6256         CrossProduct (normal, diff, right1);
6257         VectorNormalize (right1);
6258
6259         // calculate 'right' vector for end
6260         VectorSubtract (r_refdef.view.origin, org2, diff);
6261         CrossProduct (normal, diff, right2);
6262         VectorNormalize (right2);
6263
6264         vert[ 0] = org1[0] + width * right1[0];
6265         vert[ 1] = org1[1] + width * right1[1];
6266         vert[ 2] = org1[2] + width * right1[2];
6267         vert[ 3] = org1[0] - width * right1[0];
6268         vert[ 4] = org1[1] - width * right1[1];
6269         vert[ 5] = org1[2] - width * right1[2];
6270         vert[ 6] = org2[0] - width * right2[0];
6271         vert[ 7] = org2[1] - width * right2[1];
6272         vert[ 8] = org2[2] - width * right2[2];
6273         vert[ 9] = org2[0] + width * right2[0];
6274         vert[10] = org2[1] + width * right2[1];
6275         vert[11] = org2[2] + width * right2[2];
6276 }
6277
6278 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)
6279 {
6280         vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6281         vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6282         vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6283         vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6284         vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6285         vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6286         vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6287         vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6288         vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6289         vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6290         vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6291         vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6292 }
6293
6294 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6295 {
6296         int i;
6297         float *vertex3f;
6298         float v[3];
6299         VectorSet(v, x, y, z);
6300         for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6301                 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6302                         break;
6303         if (i == mesh->numvertices)
6304         {
6305                 if (mesh->numvertices < mesh->maxvertices)
6306                 {
6307                         VectorCopy(v, vertex3f);
6308                         mesh->numvertices++;
6309                 }
6310                 return mesh->numvertices;
6311         }
6312         else
6313                 return i;
6314 }
6315
6316 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6317 {
6318         int i;
6319         int *e, element[3];
6320         element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6321         element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6322         e = mesh->element3i + mesh->numtriangles * 3;
6323         for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6324         {
6325                 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6326                 if (mesh->numtriangles < mesh->maxtriangles)
6327                 {
6328                         *e++ = element[0];
6329                         *e++ = element[1];
6330                         *e++ = element[2];
6331                         mesh->numtriangles++;
6332                 }
6333                 element[1] = element[2];
6334         }
6335 }
6336
6337 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6338 {
6339         int i;
6340         int *e, element[3];
6341         element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6342         element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6343         e = mesh->element3i + mesh->numtriangles * 3;
6344         for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6345         {
6346                 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6347                 if (mesh->numtriangles < mesh->maxtriangles)
6348                 {
6349                         *e++ = element[0];
6350                         *e++ = element[1];
6351                         *e++ = element[2];
6352                         mesh->numtriangles++;
6353                 }
6354                 element[1] = element[2];
6355         }
6356 }
6357
6358 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6359 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6360 {
6361         int planenum, planenum2;
6362         int w;
6363         int tempnumpoints;
6364         mplane_t *plane, *plane2;
6365         double maxdist;
6366         double temppoints[2][256*3];
6367         // figure out how large a bounding box we need to properly compute this brush
6368         maxdist = 0;
6369         for (w = 0;w < numplanes;w++)
6370                 maxdist = max(maxdist, fabs(planes[w].dist));
6371         // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6372         maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6373         for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6374         {
6375                 w = 0;
6376                 tempnumpoints = 4;
6377                 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6378                 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6379                 {
6380                         if (planenum2 == planenum)
6381                                 continue;
6382                         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);
6383                         w = !w;
6384                 }
6385                 if (tempnumpoints < 3)
6386                         continue;
6387                 // generate elements forming a triangle fan for this polygon
6388                 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6389         }
6390 }
6391
6392 static qboolean R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6393 {
6394         if(parms[0] == 0 && parms[1] == 0)
6395                 return false;
6396         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6397                 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6398                         return false;
6399         return true;
6400 }
6401
6402 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6403 {
6404         double index, f;
6405         index = parms[2] + rsurface.shadertime * parms[3];
6406         index -= floor(index);
6407         switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6408         {
6409         default:
6410         case Q3WAVEFUNC_NONE:
6411         case Q3WAVEFUNC_NOISE:
6412         case Q3WAVEFUNC_COUNT:
6413                 f = 0;
6414                 break;
6415         case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6416         case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6417         case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6418         case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6419         case Q3WAVEFUNC_TRIANGLE:
6420                 index *= 4;
6421                 f = index - floor(index);
6422                 if (index < 1)
6423                 {
6424                         // f = f;
6425                 }
6426                 else if (index < 2)
6427                         f = 1 - f;
6428                 else if (index < 3)
6429                         f = -f;
6430                 else
6431                         f = -(1 - f);
6432                 break;
6433         }
6434         f = parms[0] + parms[1] * f;
6435         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6436                 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6437         return (float) f;
6438 }
6439
6440 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6441 {
6442         int w, h, idx;
6443         float shadertime;
6444         float f;
6445         float offsetd[2];
6446         float tcmat[12];
6447         matrix4x4_t matrix, temp;
6448         // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6449         // it's better to have one huge fixup every 9 hours than gradual
6450         // degradation over time which looks consistently bad after many hours.
6451         //
6452         // tcmod scroll in particular suffers from this degradation which can't be
6453         // effectively worked around even with floor() tricks because we don't
6454         // know if tcmod scroll is the last tcmod being applied, and for clampmap
6455         // a workaround involving floor() would be incorrect anyway...
6456         shadertime = rsurface.shadertime;
6457         if (shadertime >= 32768.0f)
6458                 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6459         switch(tcmod->tcmod)
6460         {
6461                 case Q3TCMOD_COUNT:
6462                 case Q3TCMOD_NONE:
6463                         if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6464                                 matrix = r_waterscrollmatrix;
6465                         else
6466                                 matrix = identitymatrix;
6467                         break;
6468                 case Q3TCMOD_ENTITYTRANSLATE:
6469                         // this is used in Q3 to allow the gamecode to control texcoord
6470                         // scrolling on the entity, which is not supported in darkplaces yet.
6471                         Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6472                         break;
6473                 case Q3TCMOD_ROTATE:
6474                         Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6475                         Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6476                         Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6477                         break;
6478                 case Q3TCMOD_SCALE:
6479                         Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6480                         break;
6481                 case Q3TCMOD_SCROLL:
6482                         // this particular tcmod is a "bug for bug" compatible one with regards to
6483                         // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6484                         // specifically did the wrapping and so we must mimic that...
6485                         offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6486                         offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6487                         Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6488                         break;
6489                 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6490                         w = (int) tcmod->parms[0];
6491                         h = (int) tcmod->parms[1];
6492                         f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6493                         f = f - floor(f);
6494                         idx = (int) floor(f * w * h);
6495                         Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6496                         break;
6497                 case Q3TCMOD_STRETCH:
6498                         f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6499                         Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6500                         break;
6501                 case Q3TCMOD_TRANSFORM:
6502                         VectorSet(tcmat +  0, tcmod->parms[0], tcmod->parms[1], 0);
6503                         VectorSet(tcmat +  3, tcmod->parms[2], tcmod->parms[3], 0);
6504                         VectorSet(tcmat +  6, 0                   , 0                , 1);
6505                         VectorSet(tcmat +  9, tcmod->parms[4], tcmod->parms[5], 0);
6506                         Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6507                         break;
6508                 case Q3TCMOD_TURBULENT:
6509                         // this is handled in the RSurf_PrepareVertices function
6510                         matrix = identitymatrix;
6511                         break;
6512         }
6513         temp = *texmatrix;
6514         Matrix4x4_Concat(texmatrix, &matrix, &temp);
6515 }
6516
6517 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6518 {
6519         int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6520         char name[MAX_QPATH];
6521         skinframe_t *skinframe;
6522         unsigned char pixels[296*194];
6523         strlcpy(cache->name, skinname, sizeof(cache->name));
6524         dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6525         if (developer_loading.integer)
6526                 Con_Printf("loading %s\n", name);
6527         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6528         if (!skinframe || !skinframe->base)
6529         {
6530                 unsigned char *f;
6531                 fs_offset_t filesize;
6532                 skinframe = NULL;
6533                 f = FS_LoadFile(name, tempmempool, true, &filesize);
6534                 if (f)
6535                 {
6536                         if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6537                                 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6538                         Mem_Free(f);
6539                 }
6540         }
6541         cache->skinframe = skinframe;
6542 }
6543
6544 texture_t *R_GetCurrentTexture(texture_t *t)
6545 {
6546         int i, q;
6547         const entity_render_t *ent = rsurface.entity;
6548         dp_model_t *model = ent->model; // when calling this, ent must not be NULL
6549         q3shaderinfo_layer_tcmod_t *tcmod;
6550         float specularscale = 0.0f;
6551
6552         if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6553                 return t->currentframe;
6554         t->update_lastrenderframe = r_textureframe;
6555         t->update_lastrenderentity = (void *)ent;
6556
6557         if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6558                 t->camera_entity = ent->entitynumber;
6559         else
6560                 t->camera_entity = 0;
6561
6562         // switch to an alternate material if this is a q1bsp animated material
6563         {
6564                 texture_t *texture = t;
6565                 int s = rsurface.ent_skinnum;
6566                 if ((unsigned int)s >= (unsigned int)model->numskins)
6567                         s = 0;
6568                 if (model->skinscenes)
6569                 {
6570                         if (model->skinscenes[s].framecount > 1)
6571                                 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6572                         else
6573                                 s = model->skinscenes[s].firstframe;
6574                 }
6575                 if (s > 0)
6576                         t = t + s * model->num_surfaces;
6577                 if (t->animated)
6578                 {
6579                         // use an alternate animation if the entity's frame is not 0,
6580                         // and only if the texture has an alternate animation
6581                         if (t->animated == 2) // q2bsp
6582                                 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6583                         else if (rsurface.ent_alttextures && t->anim_total[1])
6584                                 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6585                         else
6586                                 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6587                 }
6588                 texture->currentframe = t;
6589         }
6590
6591         // update currentskinframe to be a qw skin or animation frame
6592         if (rsurface.ent_qwskin >= 0)
6593         {
6594                 i = rsurface.ent_qwskin;
6595                 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6596                 {
6597                         r_qwskincache_size = cl.maxclients;
6598                         if (r_qwskincache)
6599                                 Mem_Free(r_qwskincache);
6600                         r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6601                 }
6602                 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6603                         R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6604                 t->currentskinframe = r_qwskincache[i].skinframe;
6605                 if (t->materialshaderpass && t->currentskinframe == NULL)
6606                         t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6607         }
6608         else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6609                 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6610         if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6611                 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6612
6613         t->currentmaterialflags = t->basematerialflags;
6614         t->currentalpha = rsurface.entity->alpha * t->basealpha;
6615         if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_water.integer || r_novis.integer || r_trippy.integer))
6616                 t->currentalpha *= r_wateralpha.value;
6617         if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6618                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6619         if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6620                 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6621
6622         // decide on which type of lighting to use for this surface
6623         if (rsurface.entity->render_modellight_forced)
6624                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6625         if (rsurface.entity->render_rtlight_disabled)
6626                 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6627         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6628         {
6629                 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6630                 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NORTLIGHT;
6631                 for (q = 0; q < 3; q++)
6632                 {
6633                         t->render_glowmod[q] = rsurface.entity->glowmod[q];
6634                         t->render_modellight_lightdir[q] = q == 2;
6635                         t->render_modellight_ambient[q] = 1;
6636                         t->render_modellight_diffuse[q] = 0;
6637                         t->render_modellight_specular[q] = 0;
6638                         t->render_lightmap_ambient[q] = 0;
6639                         t->render_lightmap_diffuse[q] = 0;
6640                         t->render_lightmap_specular[q] = 0;
6641                         t->render_rtlight_diffuse[q] = 0;
6642                         t->render_rtlight_specular[q] = 0;
6643                 }
6644         }
6645         else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6646         {
6647                 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6648                 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT;
6649                 for (q = 0; q < 3; q++)
6650                 {
6651                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6652                         t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6653                         t->render_modellight_lightdir[q] = q == 2;
6654                         t->render_modellight_diffuse[q] = 0;
6655                         t->render_modellight_specular[q] = 0;
6656                         t->render_lightmap_ambient[q] = 0;
6657                         t->render_lightmap_diffuse[q] = 0;
6658                         t->render_lightmap_specular[q] = 0;
6659                         t->render_rtlight_diffuse[q] = 0;
6660                         t->render_rtlight_specular[q] = 0;
6661                 }
6662         }
6663         else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6664         {
6665                 // ambient + single direction light (modellight)
6666                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6667                 for (q = 0; q < 3; q++)
6668                 {
6669                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6670                         t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6671                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6672                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6673                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6674                         t->render_lightmap_ambient[q] = 0;
6675                         t->render_lightmap_diffuse[q] = 0;
6676                         t->render_lightmap_specular[q] = 0;
6677                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6678                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6679                 }
6680         }
6681         else
6682         {
6683                 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6684                 for (q = 0; q < 3; q++)
6685                 {
6686                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6687                         t->render_modellight_lightdir[q] = q == 2;
6688                         t->render_modellight_ambient[q] = 0;
6689                         t->render_modellight_diffuse[q] = 0;
6690                         t->render_modellight_specular[q] = 0;
6691                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6692                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6693                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6694                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6695                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6696                 }
6697         }
6698
6699         if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6700         {
6701                 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6702                 // attribute, we punt it to the lightmap path and hope for the best,
6703                 // but lighting doesn't work.
6704                 //
6705                 // FIXME: this is fine for effects but CSQC polygons should be subject
6706                 // to lighting.
6707                 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6708                 for (q = 0; q < 3; q++)
6709                 {
6710                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6711                         t->render_modellight_lightdir[q] = q == 2;
6712                         t->render_modellight_ambient[q] = 0;
6713                         t->render_modellight_diffuse[q] = 0;
6714                         t->render_modellight_specular[q] = 0;
6715                         t->render_lightmap_ambient[q] = 0;
6716                         t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6717                         t->render_lightmap_specular[q] = 0;
6718                         t->render_rtlight_diffuse[q] = 0;
6719                         t->render_rtlight_specular[q] = 0;
6720                 }
6721         }
6722
6723         for (q = 0; q < 3; q++)
6724         {
6725                 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6726                 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6727         }
6728
6729         if (rsurface.ent_flags & RENDER_ADDITIVE)
6730                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6731         else if (t->currentalpha < 1)
6732                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6733         // LadyHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6734         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6735                 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6736         if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6737                 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6738         if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6739                 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6740         if (t->backgroundshaderpass)
6741                 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6742         if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6743         {
6744                 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6745                         t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6746         }
6747         else
6748                 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6749         if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6750         {
6751                 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6752                 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6753         }
6754         if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6755                 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6756
6757         // there is no tcmod
6758         if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6759         {
6760                 t->currenttexmatrix = r_waterscrollmatrix;
6761                 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6762         }
6763         else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6764         {
6765                 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6766                 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6767         }
6768
6769         if (t->materialshaderpass)
6770                 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6771                         R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6772
6773         t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6774         if (t->currentskinframe->qpixels)
6775                 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6776         t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6777         if (!t->basetexture)
6778                 t->basetexture = r_texture_notexture;
6779         t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6780         t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6781         t->nmaptexture = t->currentskinframe->nmap;
6782         if (!t->nmaptexture)
6783                 t->nmaptexture = r_texture_blanknormalmap;
6784         t->glosstexture = r_texture_black;
6785         t->glowtexture = t->currentskinframe->glow;
6786         t->fogtexture = t->currentskinframe->fog;
6787         t->reflectmasktexture = t->currentskinframe->reflect;
6788         if (t->backgroundshaderpass)
6789         {
6790                 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6791                         R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6792                 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6793                 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6794                 t->backgroundglosstexture = r_texture_black;
6795                 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6796                 if (!t->backgroundnmaptexture)
6797                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6798                 // make sure that if glow is going to be used, both textures are not NULL
6799                 if (!t->backgroundglowtexture && t->glowtexture)
6800                         t->backgroundglowtexture = r_texture_black;
6801                 if (!t->glowtexture && t->backgroundglowtexture)
6802                         t->glowtexture = r_texture_black;
6803         }
6804         else
6805         {
6806                 t->backgroundbasetexture = r_texture_white;
6807                 t->backgroundnmaptexture = r_texture_blanknormalmap;
6808                 t->backgroundglosstexture = r_texture_black;
6809                 t->backgroundglowtexture = NULL;
6810         }
6811         t->specularpower = r_shadow_glossexponent.value;
6812         // TODO: store reference values for these in the texture?
6813         if (r_shadow_gloss.integer > 0)
6814         {
6815                 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
6816                 {
6817                         if (r_shadow_glossintensity.value > 0)
6818                         {
6819                                 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
6820                                 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
6821                                 specularscale = r_shadow_glossintensity.value;
6822                         }
6823                 }
6824                 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
6825                 {
6826                         t->glosstexture = r_texture_white;
6827                         t->backgroundglosstexture = r_texture_white;
6828                         specularscale = r_shadow_gloss2intensity.value;
6829                         t->specularpower = r_shadow_gloss2exponent.value;
6830                 }
6831         }
6832         specularscale *= t->specularscalemod;
6833         t->specularpower *= t->specularpowermod;
6834
6835         // lightmaps mode looks bad with dlights using actual texturing, so turn
6836         // off the colormap and glossmap, but leave the normalmap on as it still
6837         // accurately represents the shading involved
6838         if (gl_lightmaps.integer)
6839         {
6840                 t->basetexture = r_texture_grey128;
6841                 t->pantstexture = r_texture_black;
6842                 t->shirttexture = r_texture_black;
6843                 if (gl_lightmaps.integer < 2)
6844                         t->nmaptexture = r_texture_blanknormalmap;
6845                 t->glosstexture = r_texture_black;
6846                 t->glowtexture = NULL;
6847                 t->fogtexture = NULL;
6848                 t->reflectmasktexture = NULL;
6849                 t->backgroundbasetexture = NULL;
6850                 if (gl_lightmaps.integer < 2)
6851                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6852                 t->backgroundglosstexture = r_texture_black;
6853                 t->backgroundglowtexture = NULL;
6854                 specularscale = 0;
6855                 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
6856         }
6857
6858         if (specularscale != 1.0f)
6859         {
6860                 for (q = 0; q < 3; q++)
6861                 {
6862                         t->render_modellight_specular[q] *= specularscale;
6863                         t->render_lightmap_specular[q] *= specularscale;
6864                         t->render_rtlight_specular[q] *= specularscale;
6865                 }
6866         }
6867
6868         t->currentblendfunc[0] = GL_ONE;
6869         t->currentblendfunc[1] = GL_ZERO;
6870         if (t->currentmaterialflags & MATERIALFLAG_ADD)
6871         {
6872                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6873                 t->currentblendfunc[1] = GL_ONE;
6874         }
6875         else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
6876         {
6877                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6878                 t->currentblendfunc[1] = GL_ONE_MINUS_SRC_ALPHA;
6879         }
6880         else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6881         {
6882                 t->currentblendfunc[0] = t->customblendfunc[0];
6883                 t->currentblendfunc[1] = t->customblendfunc[1];
6884         }
6885
6886         return t;
6887 }
6888
6889 rsurfacestate_t rsurface;
6890
6891 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
6892 {
6893         dp_model_t *model = ent->model;
6894         //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
6895         //      return;
6896         rsurface.entity = (entity_render_t *)ent;
6897         rsurface.skeleton = ent->skeleton;
6898         memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
6899         rsurface.ent_skinnum = ent->skinnum;
6900         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;
6901         rsurface.ent_flags = ent->flags;
6902         if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
6903                 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
6904         rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
6905         rsurface.matrix = ent->matrix;
6906         rsurface.inversematrix = ent->inversematrix;
6907         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
6908         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
6909         R_EntityMatrix(&rsurface.matrix);
6910         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
6911         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
6912         rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
6913         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
6914         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
6915         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
6916         memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
6917         rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
6918         rsurface.basepolygonfactor = r_refdef.polygonfactor;
6919         rsurface.basepolygonoffset = r_refdef.polygonoffset;
6920         if (ent->model->brush.submodel && !prepass)
6921         {
6922                 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
6923                 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
6924         }
6925         // if the animcache code decided it should use the shader path, skip the deform step
6926         rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
6927         rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
6928         rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
6929         rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
6930         rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
6931         if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
6932         {
6933                 if (ent->animcache_vertex3f)
6934                 {
6935                         r_refdef.stats[r_stat_batch_entitycache_count]++;
6936                         r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
6937                         r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
6938                         r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
6939                         rsurface.modelvertex3f = ent->animcache_vertex3f;
6940                         rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
6941                         rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
6942                         rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
6943                         rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
6944                         rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
6945                         rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
6946                         rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
6947                         rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
6948                         rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
6949                         rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
6950                         rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
6951                 }
6952                 else if (wanttangents)
6953                 {
6954                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
6955                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
6956                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
6957                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
6958                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6959                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6960                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6961                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6962                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
6963                         rsurface.modelvertex3f_vertexbuffer = NULL;
6964                         rsurface.modelvertex3f_bufferoffset = 0;
6965                         rsurface.modelvertex3f_vertexbuffer = 0;
6966                         rsurface.modelvertex3f_bufferoffset = 0;
6967                         rsurface.modelsvector3f_vertexbuffer = 0;
6968                         rsurface.modelsvector3f_bufferoffset = 0;
6969                         rsurface.modeltvector3f_vertexbuffer = 0;
6970                         rsurface.modeltvector3f_bufferoffset = 0;
6971                         rsurface.modelnormal3f_vertexbuffer = 0;
6972                         rsurface.modelnormal3f_bufferoffset = 0;
6973                 }
6974                 else if (wantnormals)
6975                 {
6976                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
6977                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
6978                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
6979                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
6980                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6981                         rsurface.modelsvector3f = NULL;
6982                         rsurface.modeltvector3f = NULL;
6983                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6984                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
6985                         rsurface.modelvertex3f_vertexbuffer = NULL;
6986                         rsurface.modelvertex3f_bufferoffset = 0;
6987                         rsurface.modelvertex3f_vertexbuffer = 0;
6988                         rsurface.modelvertex3f_bufferoffset = 0;
6989                         rsurface.modelsvector3f_vertexbuffer = 0;
6990                         rsurface.modelsvector3f_bufferoffset = 0;
6991                         rsurface.modeltvector3f_vertexbuffer = 0;
6992                         rsurface.modeltvector3f_bufferoffset = 0;
6993                         rsurface.modelnormal3f_vertexbuffer = 0;
6994                         rsurface.modelnormal3f_bufferoffset = 0;
6995                 }
6996                 else
6997                 {
6998                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
6999                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7000                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7001                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7002                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7003                         rsurface.modelsvector3f = NULL;
7004                         rsurface.modeltvector3f = NULL;
7005                         rsurface.modelnormal3f = NULL;
7006                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7007                         rsurface.modelvertex3f_vertexbuffer = NULL;
7008                         rsurface.modelvertex3f_bufferoffset = 0;
7009                         rsurface.modelvertex3f_vertexbuffer = 0;
7010                         rsurface.modelvertex3f_bufferoffset = 0;
7011                         rsurface.modelsvector3f_vertexbuffer = 0;
7012                         rsurface.modelsvector3f_bufferoffset = 0;
7013                         rsurface.modeltvector3f_vertexbuffer = 0;
7014                         rsurface.modeltvector3f_bufferoffset = 0;
7015                         rsurface.modelnormal3f_vertexbuffer = 0;
7016                         rsurface.modelnormal3f_bufferoffset = 0;
7017                 }
7018                 rsurface.modelgeneratedvertex = true;
7019         }
7020         else
7021         {
7022                 if (rsurface.entityskeletaltransform3x4)
7023                 {
7024                         r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7025                         r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7026                         r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7027                         r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7028                 }
7029                 else
7030                 {
7031                         r_refdef.stats[r_stat_batch_entitystatic_count]++;
7032                         r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7033                         r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7034                         r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7035                 }
7036                 rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
7037                 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.data_vertex3f_vertexbuffer;
7038                 rsurface.modelvertex3f_bufferoffset = model->surfmesh.data_vertex3f_bufferoffset;
7039                 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7040                 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.data_svector3f_vertexbuffer;
7041                 rsurface.modelsvector3f_bufferoffset = model->surfmesh.data_svector3f_bufferoffset;
7042                 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7043                 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.data_tvector3f_vertexbuffer;
7044                 rsurface.modeltvector3f_bufferoffset = model->surfmesh.data_tvector3f_bufferoffset;
7045                 rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
7046                 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.data_normal3f_vertexbuffer;
7047                 rsurface.modelnormal3f_bufferoffset = model->surfmesh.data_normal3f_bufferoffset;
7048                 rsurface.modelgeneratedvertex = false;
7049         }
7050         rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
7051         rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.data_lightmapcolor4f_vertexbuffer;
7052         rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.data_lightmapcolor4f_bufferoffset;
7053         rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
7054         rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.data_texcoordtexture2f_vertexbuffer;
7055         rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.data_texcoordtexture2f_bufferoffset;
7056         rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
7057         rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.data_texcoordlightmap2f_vertexbuffer;
7058         rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.data_texcoordlightmap2f_bufferoffset;
7059         rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7060         rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.data_skeletalindex4ub_vertexbuffer;
7061         rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.data_skeletalindex4ub_bufferoffset;
7062         rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7063         rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.data_skeletalweight4ub_vertexbuffer;
7064         rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.data_skeletalweight4ub_bufferoffset;
7065         rsurface.modelelement3i = model->surfmesh.data_element3i;
7066         rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7067         rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7068         rsurface.modelelement3s = model->surfmesh.data_element3s;
7069         rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7070         rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7071         rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7072         rsurface.modelnumvertices = model->surfmesh.num_vertices;
7073         rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7074         rsurface.modelsurfaces = model->data_surfaces;
7075         rsurface.batchgeneratedvertex = false;
7076         rsurface.batchfirstvertex = 0;
7077         rsurface.batchnumvertices = 0;
7078         rsurface.batchfirsttriangle = 0;
7079         rsurface.batchnumtriangles = 0;
7080         rsurface.batchvertex3f  = NULL;
7081         rsurface.batchvertex3f_vertexbuffer = NULL;
7082         rsurface.batchvertex3f_bufferoffset = 0;
7083         rsurface.batchsvector3f = NULL;
7084         rsurface.batchsvector3f_vertexbuffer = NULL;
7085         rsurface.batchsvector3f_bufferoffset = 0;
7086         rsurface.batchtvector3f = NULL;
7087         rsurface.batchtvector3f_vertexbuffer = NULL;
7088         rsurface.batchtvector3f_bufferoffset = 0;
7089         rsurface.batchnormal3f  = NULL;
7090         rsurface.batchnormal3f_vertexbuffer = NULL;
7091         rsurface.batchnormal3f_bufferoffset = 0;
7092         rsurface.batchlightmapcolor4f = NULL;
7093         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7094         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7095         rsurface.batchtexcoordtexture2f = NULL;
7096         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7097         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7098         rsurface.batchtexcoordlightmap2f = NULL;
7099         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7100         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7101         rsurface.batchskeletalindex4ub = NULL;
7102         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7103         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7104         rsurface.batchskeletalweight4ub = NULL;
7105         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7106         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7107         rsurface.batchelement3i = NULL;
7108         rsurface.batchelement3i_indexbuffer = NULL;
7109         rsurface.batchelement3i_bufferoffset = 0;
7110         rsurface.batchelement3s = NULL;
7111         rsurface.batchelement3s_indexbuffer = NULL;
7112         rsurface.batchelement3s_bufferoffset = 0;
7113         rsurface.forcecurrenttextureupdate = false;
7114 }
7115
7116 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)
7117 {
7118         rsurface.entity = r_refdef.scene.worldentity;
7119         if (r != 1.0f || g != 1.0f || b != 1.0f || a != 1.0f) {
7120                 // HACK to provide a valid entity with modded colors to R_GetCurrentTexture.
7121                 // A better approach could be making this copy only once per frame.
7122                 static entity_render_t custom_entity;
7123                 int q;
7124                 custom_entity = *rsurface.entity;
7125                 for (q = 0; q < 3; ++q) {
7126                         float colormod = q == 0 ? r : q == 1 ? g : b;
7127                         custom_entity.render_fullbright[q] *= colormod;
7128                         custom_entity.render_modellight_ambient[q] *= colormod;
7129                         custom_entity.render_modellight_diffuse[q] *= colormod;
7130                         custom_entity.render_lightmap_ambient[q] *= colormod;
7131                         custom_entity.render_lightmap_diffuse[q] *= colormod;
7132                         custom_entity.render_rtlight_diffuse[q] *= colormod;
7133                 }
7134                 custom_entity.alpha *= a;
7135                 rsurface.entity = &custom_entity;
7136         }
7137         rsurface.skeleton = NULL;
7138         rsurface.ent_skinnum = 0;
7139         rsurface.ent_qwskin = -1;
7140         rsurface.ent_flags = entflags;
7141         rsurface.shadertime = r_refdef.scene.time - shadertime;
7142         rsurface.modelnumvertices = numvertices;
7143         rsurface.modelnumtriangles = numtriangles;
7144         rsurface.matrix = *matrix;
7145         rsurface.inversematrix = *inversematrix;
7146         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7147         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7148         R_EntityMatrix(&rsurface.matrix);
7149         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7150         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7151         rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7152         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7153         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7154         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7155         memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7156         rsurface.frameblend[0].lerp = 1;
7157         rsurface.ent_alttextures = false;
7158         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7159         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7160         rsurface.entityskeletaltransform3x4 = NULL;
7161         rsurface.entityskeletaltransform3x4buffer = NULL;
7162         rsurface.entityskeletaltransform3x4offset = 0;
7163         rsurface.entityskeletaltransform3x4size = 0;
7164         rsurface.entityskeletalnumtransforms = 0;
7165         r_refdef.stats[r_stat_batch_entitycustom_count]++;
7166         r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7167         r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7168         r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7169         if (wanttangents)
7170         {
7171                 rsurface.modelvertex3f = (float *)vertex3f;
7172                 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7173                 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7174                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7175         }
7176         else if (wantnormals)
7177         {
7178                 rsurface.modelvertex3f = (float *)vertex3f;
7179                 rsurface.modelsvector3f = NULL;
7180                 rsurface.modeltvector3f = NULL;
7181                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7182         }
7183         else
7184         {
7185                 rsurface.modelvertex3f = (float *)vertex3f;
7186                 rsurface.modelsvector3f = NULL;
7187                 rsurface.modeltvector3f = NULL;
7188                 rsurface.modelnormal3f = NULL;
7189         }
7190         rsurface.modelvertex3f_vertexbuffer = 0;
7191         rsurface.modelvertex3f_bufferoffset = 0;
7192         rsurface.modelsvector3f_vertexbuffer = 0;
7193         rsurface.modelsvector3f_bufferoffset = 0;
7194         rsurface.modeltvector3f_vertexbuffer = 0;
7195         rsurface.modeltvector3f_bufferoffset = 0;
7196         rsurface.modelnormal3f_vertexbuffer = 0;
7197         rsurface.modelnormal3f_bufferoffset = 0;
7198         rsurface.modelgeneratedvertex = true;
7199         rsurface.modellightmapcolor4f  = (float *)color4f;
7200         rsurface.modellightmapcolor4f_vertexbuffer = 0;
7201         rsurface.modellightmapcolor4f_bufferoffset = 0;
7202         rsurface.modeltexcoordtexture2f  = (float *)texcoord2f;
7203         rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7204         rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7205         rsurface.modeltexcoordlightmap2f  = NULL;
7206         rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7207         rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7208         rsurface.modelskeletalindex4ub = NULL;
7209         rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7210         rsurface.modelskeletalindex4ub_bufferoffset = 0;
7211         rsurface.modelskeletalweight4ub = NULL;
7212         rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7213         rsurface.modelskeletalweight4ub_bufferoffset = 0;
7214         rsurface.modelelement3i = (int *)element3i;
7215         rsurface.modelelement3i_indexbuffer = NULL;
7216         rsurface.modelelement3i_bufferoffset = 0;
7217         rsurface.modelelement3s = (unsigned short *)element3s;
7218         rsurface.modelelement3s_indexbuffer = NULL;
7219         rsurface.modelelement3s_bufferoffset = 0;
7220         rsurface.modellightmapoffsets = NULL;
7221         rsurface.modelsurfaces = NULL;
7222         rsurface.batchgeneratedvertex = false;
7223         rsurface.batchfirstvertex = 0;
7224         rsurface.batchnumvertices = 0;
7225         rsurface.batchfirsttriangle = 0;
7226         rsurface.batchnumtriangles = 0;
7227         rsurface.batchvertex3f  = NULL;
7228         rsurface.batchvertex3f_vertexbuffer = NULL;
7229         rsurface.batchvertex3f_bufferoffset = 0;
7230         rsurface.batchsvector3f = NULL;
7231         rsurface.batchsvector3f_vertexbuffer = NULL;
7232         rsurface.batchsvector3f_bufferoffset = 0;
7233         rsurface.batchtvector3f = NULL;
7234         rsurface.batchtvector3f_vertexbuffer = NULL;
7235         rsurface.batchtvector3f_bufferoffset = 0;
7236         rsurface.batchnormal3f  = NULL;
7237         rsurface.batchnormal3f_vertexbuffer = NULL;
7238         rsurface.batchnormal3f_bufferoffset = 0;
7239         rsurface.batchlightmapcolor4f = NULL;
7240         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7241         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7242         rsurface.batchtexcoordtexture2f = NULL;
7243         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7244         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7245         rsurface.batchtexcoordlightmap2f = NULL;
7246         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7247         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7248         rsurface.batchskeletalindex4ub = NULL;
7249         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7250         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7251         rsurface.batchskeletalweight4ub = NULL;
7252         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7253         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7254         rsurface.batchelement3i = NULL;
7255         rsurface.batchelement3i_indexbuffer = NULL;
7256         rsurface.batchelement3i_bufferoffset = 0;
7257         rsurface.batchelement3s = NULL;
7258         rsurface.batchelement3s_indexbuffer = NULL;
7259         rsurface.batchelement3s_bufferoffset = 0;
7260         rsurface.forcecurrenttextureupdate = true;
7261
7262         if (rsurface.modelnumvertices && rsurface.modelelement3i)
7263         {
7264                 if ((wantnormals || wanttangents) && !normal3f)
7265                 {
7266                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7267                         Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7268                 }
7269                 if (wanttangents && !svector3f)
7270                 {
7271                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7272                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7273                         Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7274                 }
7275         }
7276 }
7277
7278 float RSurf_FogPoint(const float *v)
7279 {
7280         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7281         float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7282         float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7283         float FogHeightFade = r_refdef.fogheightfade;
7284         float fogfrac;
7285         unsigned int fogmasktableindex;
7286         if (r_refdef.fogplaneviewabove)
7287                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7288         else
7289                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7290         fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7291         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7292 }
7293
7294 float RSurf_FogVertex(const float *v)
7295 {
7296         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7297         float FogPlaneViewDist = rsurface.fogplaneviewdist;
7298         float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7299         float FogHeightFade = rsurface.fogheightfade;
7300         float fogfrac;
7301         unsigned int fogmasktableindex;
7302         if (r_refdef.fogplaneviewabove)
7303                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7304         else
7305                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7306         fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7307         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7308 }
7309
7310 void RSurf_UploadBuffersForBatch(void)
7311 {
7312         // 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)
7313         // note that if rsurface.batchvertex3f_vertexbuffer is NULL, dynamicvertex is forced as we don't account for the proper base vertex here.
7314         if (rsurface.batchvertex3f && !rsurface.batchvertex3f_vertexbuffer)
7315                 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
7316         if (rsurface.batchsvector3f && !rsurface.batchsvector3f_vertexbuffer)
7317                 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
7318         if (rsurface.batchtvector3f && !rsurface.batchtvector3f_vertexbuffer)
7319                 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
7320         if (rsurface.batchnormal3f && !rsurface.batchnormal3f_vertexbuffer)
7321                 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
7322         if (rsurface.batchlightmapcolor4f && !rsurface.batchlightmapcolor4f_vertexbuffer)
7323                 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
7324         if (rsurface.batchtexcoordtexture2f && !rsurface.batchtexcoordtexture2f_vertexbuffer)
7325                 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
7326         if (rsurface.batchtexcoordlightmap2f && !rsurface.batchtexcoordlightmap2f_vertexbuffer)
7327                 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
7328         if (rsurface.batchskeletalindex4ub && !rsurface.batchskeletalindex4ub_vertexbuffer)
7329                 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
7330         if (rsurface.batchskeletalweight4ub && !rsurface.batchskeletalweight4ub_vertexbuffer)
7331                 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
7332
7333         if (rsurface.batchelement3s && !rsurface.batchelement3s_indexbuffer)
7334                 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
7335         else if (rsurface.batchelement3i && !rsurface.batchelement3i_indexbuffer)
7336                 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
7337
7338         R_Mesh_VertexPointer(     3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
7339         R_Mesh_ColorPointer(      4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
7340         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
7341         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
7342         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
7343         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
7344         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
7345         R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
7346         R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
7347         R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
7348 }
7349
7350 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7351 {
7352         int i;
7353         for (i = 0;i < numelements;i++)
7354                 outelement3i[i] = inelement3i[i] + adjust;
7355 }
7356
7357 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7358 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7359 {
7360         int deformindex;
7361         int firsttriangle;
7362         int numtriangles;
7363         int firstvertex;
7364         int endvertex;
7365         int numvertices;
7366         int surfacefirsttriangle;
7367         int surfacenumtriangles;
7368         int surfacefirstvertex;
7369         int surfaceendvertex;
7370         int surfacenumvertices;
7371         int batchnumsurfaces = texturenumsurfaces;
7372         int batchnumvertices;
7373         int batchnumtriangles;
7374         int i, j;
7375         qboolean gaps;
7376         qboolean dynamicvertex;
7377         float amplitude;
7378         float animpos;
7379         float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7380         float waveparms[4];
7381         unsigned char *ub;
7382         q3shaderinfo_deform_t *deform;
7383         const msurface_t *surface, *firstsurface;
7384         if (!texturenumsurfaces)
7385                 return;
7386         // find vertex range of this surface batch
7387         gaps = false;
7388         firstsurface = texturesurfacelist[0];
7389         firsttriangle = firstsurface->num_firsttriangle;
7390         batchnumvertices = 0;
7391         batchnumtriangles = 0;
7392         firstvertex = endvertex = firstsurface->num_firstvertex;
7393         for (i = 0;i < texturenumsurfaces;i++)
7394         {
7395                 surface = texturesurfacelist[i];
7396                 if (surface != firstsurface + i)
7397                         gaps = true;
7398                 surfacefirstvertex = surface->num_firstvertex;
7399                 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7400                 surfacenumvertices = surface->num_vertices;
7401                 surfacenumtriangles = surface->num_triangles;
7402                 if (firstvertex > surfacefirstvertex)
7403                         firstvertex = surfacefirstvertex;
7404                 if (endvertex < surfaceendvertex)
7405                         endvertex = surfaceendvertex;
7406                 batchnumvertices += surfacenumvertices;
7407                 batchnumtriangles += surfacenumtriangles;
7408         }
7409
7410         r_refdef.stats[r_stat_batch_batches]++;
7411         if (gaps)
7412                 r_refdef.stats[r_stat_batch_withgaps]++;
7413         r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7414         r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7415         r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7416
7417         // we now know the vertex range used, and if there are any gaps in it
7418         rsurface.batchfirstvertex = firstvertex;
7419         rsurface.batchnumvertices = endvertex - firstvertex;
7420         rsurface.batchfirsttriangle = firsttriangle;
7421         rsurface.batchnumtriangles = batchnumtriangles;
7422
7423         // check if any dynamic vertex processing must occur
7424         dynamicvertex = false;
7425
7426         // we must use vertexbuffers for rendering, we can upload vertex buffers
7427         // easily enough but if the basevertex is non-zero it becomes more
7428         // difficult, so force dynamicvertex path in that case - it's suboptimal
7429         // but the most optimal case is to have the geometry sources provide their
7430         // own anyway.
7431         if (!rsurface.modelvertex3f_vertexbuffer && firstvertex != 0)
7432                 dynamicvertex = true;
7433
7434         // a cvar to force the dynamic vertex path to be taken, for debugging
7435         if (r_batch_debugdynamicvertexpath.integer)
7436         {
7437                 if (!dynamicvertex)
7438                 {
7439                         r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7440                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7441                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7442                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7443                 }
7444                 dynamicvertex = true;
7445         }
7446
7447         // if there is a chance of animated vertex colors, it's a dynamic batch
7448         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
7449         {
7450                 if (!dynamicvertex)
7451                 {
7452                         r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7453                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7454                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7455                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7456                 }
7457                 dynamicvertex = true;
7458         }
7459
7460         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7461         {
7462                 switch (deform->deform)
7463                 {
7464                 default:
7465                 case Q3DEFORM_PROJECTIONSHADOW:
7466                 case Q3DEFORM_TEXT0:
7467                 case Q3DEFORM_TEXT1:
7468                 case Q3DEFORM_TEXT2:
7469                 case Q3DEFORM_TEXT3:
7470                 case Q3DEFORM_TEXT4:
7471                 case Q3DEFORM_TEXT5:
7472                 case Q3DEFORM_TEXT6:
7473                 case Q3DEFORM_TEXT7:
7474                 case Q3DEFORM_NONE:
7475                         break;
7476                 case Q3DEFORM_AUTOSPRITE:
7477                         if (!dynamicvertex)
7478                         {
7479                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7480                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7481                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7482                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7483                         }
7484                         dynamicvertex = true;
7485                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7486                         break;
7487                 case Q3DEFORM_AUTOSPRITE2:
7488                         if (!dynamicvertex)
7489                         {
7490                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7491                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7492                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7493                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7494                         }
7495                         dynamicvertex = true;
7496                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7497                         break;
7498                 case Q3DEFORM_NORMAL:
7499                         if (!dynamicvertex)
7500                         {
7501                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7502                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7503                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7504                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7505                         }
7506                         dynamicvertex = true;
7507                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7508                         break;
7509                 case Q3DEFORM_WAVE:
7510                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7511                                 break; // if wavefunc is a nop, ignore this transform
7512                         if (!dynamicvertex)
7513                         {
7514                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7515                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7516                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7517                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7518                         }
7519                         dynamicvertex = true;
7520                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7521                         break;
7522                 case Q3DEFORM_BULGE:
7523                         if (!dynamicvertex)
7524                         {
7525                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7526                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7527                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7528                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7529                         }
7530                         dynamicvertex = true;
7531                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7532                         break;
7533                 case Q3DEFORM_MOVE:
7534                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7535                                 break; // if wavefunc is a nop, ignore this transform
7536                         if (!dynamicvertex)
7537                         {
7538                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7539                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7540                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7541                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7542                         }
7543                         dynamicvertex = true;
7544                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7545                         break;
7546                 }
7547         }
7548         if (rsurface.texture->materialshaderpass)
7549         {
7550                 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7551                 {
7552                 default:
7553                 case Q3TCGEN_TEXTURE:
7554                         break;
7555                 case Q3TCGEN_LIGHTMAP:
7556                         if (!dynamicvertex)
7557                         {
7558                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7559                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7560                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7561                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7562                         }
7563                         dynamicvertex = true;
7564                         batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7565                         break;
7566                 case Q3TCGEN_VECTOR:
7567                         if (!dynamicvertex)
7568                         {
7569                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7570                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7571                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7572                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7573                         }
7574                         dynamicvertex = true;
7575                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7576                         break;
7577                 case Q3TCGEN_ENVIRONMENT:
7578                         if (!dynamicvertex)
7579                         {
7580                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7581                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7582                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7583                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7584                         }
7585                         dynamicvertex = true;
7586                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7587                         break;
7588                 }
7589                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7590                 {
7591                         if (!dynamicvertex)
7592                         {
7593                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7594                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7595                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7596                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7597                         }
7598                         dynamicvertex = true;
7599                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7600                 }
7601         }
7602
7603         // the caller can specify BATCHNEED_NOGAPS to force a batch with
7604         // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7605         // we ensure this by treating the vertex batch as dynamic...
7606         if ((batchneed & BATCHNEED_ALWAYSCOPY) || ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0)))
7607         {
7608                 if (!dynamicvertex)
7609                 {
7610                         r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7611                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7612                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7613                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7614                 }
7615                 dynamicvertex = true;
7616         }
7617
7618         // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7619         if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7620                 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7621
7622         rsurface.batchvertex3f = rsurface.modelvertex3f;
7623         rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7624         rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7625         rsurface.batchsvector3f = rsurface.modelsvector3f;
7626         rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7627         rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7628         rsurface.batchtvector3f = rsurface.modeltvector3f;
7629         rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7630         rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7631         rsurface.batchnormal3f = rsurface.modelnormal3f;
7632         rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7633         rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7634         rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7635         rsurface.batchlightmapcolor4f_vertexbuffer  = rsurface.modellightmapcolor4f_vertexbuffer;
7636         rsurface.batchlightmapcolor4f_bufferoffset  = rsurface.modellightmapcolor4f_bufferoffset;
7637         rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7638         rsurface.batchtexcoordtexture2f_vertexbuffer  = rsurface.modeltexcoordtexture2f_vertexbuffer;
7639         rsurface.batchtexcoordtexture2f_bufferoffset  = rsurface.modeltexcoordtexture2f_bufferoffset;
7640         rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7641         rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7642         rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7643         rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7644         rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7645         rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7646         rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7647         rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7648         rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7649         rsurface.batchelement3i = rsurface.modelelement3i;
7650         rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7651         rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7652         rsurface.batchelement3s = rsurface.modelelement3s;
7653         rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7654         rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7655         rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7656         rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7657         rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7658         rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7659         rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7660
7661         // if any dynamic vertex processing has to occur in software, we copy the
7662         // entire surface list together before processing to rebase the vertices
7663         // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7664         //
7665         // if any gaps exist and we do not have a static vertex buffer, we have to
7666         // copy the surface list together to avoid wasting upload bandwidth on the
7667         // vertices in the gaps.
7668         //
7669         // if gaps exist and we have a static vertex buffer, we can choose whether
7670         // to combine the index buffer ranges into one dynamic index buffer or
7671         // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7672         //
7673         // in many cases the batch is reduced to one draw call.
7674
7675         rsurface.batchmultidraw = false;
7676         rsurface.batchmultidrawnumsurfaces = 0;
7677         rsurface.batchmultidrawsurfacelist = NULL;
7678
7679         if (!dynamicvertex)
7680         {
7681                 // static vertex data, just set pointers...
7682                 rsurface.batchgeneratedvertex = false;
7683                 // if there are gaps, we want to build a combined index buffer,
7684                 // otherwise use the original static buffer with an appropriate offset
7685                 if (gaps)
7686                 {
7687                         r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7688                         r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7689                         r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7690                         r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7691                         if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7692                         {
7693                                 rsurface.batchmultidraw = true;
7694                                 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7695                                 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7696                                 return;
7697                         }
7698                         // build a new triangle elements array for this batch
7699                         rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7700                         rsurface.batchfirsttriangle = 0;
7701                         numtriangles = 0;
7702                         for (i = 0;i < texturenumsurfaces;i++)
7703                         {
7704                                 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7705                                 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7706                                 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7707                                 numtriangles += surfacenumtriangles;
7708                         }
7709                         rsurface.batchelement3i_indexbuffer = NULL;
7710                         rsurface.batchelement3i_bufferoffset = 0;
7711                         rsurface.batchelement3s = NULL;
7712                         rsurface.batchelement3s_indexbuffer = NULL;
7713                         rsurface.batchelement3s_bufferoffset = 0;
7714                         if (endvertex <= 65536)
7715                         {
7716                                 // make a 16bit (unsigned short) index array if possible
7717                                 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7718                                 for (i = 0;i < numtriangles*3;i++)
7719                                         rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7720                         }
7721                 }
7722                 else
7723                 {
7724                         r_refdef.stats[r_stat_batch_fast_batches] += 1;
7725                         r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
7726                         r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
7727                         r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
7728                 }
7729                 return;
7730         }
7731
7732         // something needs software processing, do it for real...
7733         // we only directly handle separate array data in this case and then
7734         // generate interleaved data if needed...
7735         rsurface.batchgeneratedvertex = true;
7736         r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
7737         r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
7738         r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
7739         r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
7740
7741         // now copy the vertex data into a combined array and make an index array
7742         // (this is what Quake3 does all the time)
7743         // we also apply any skeletal animation here that would have been done in
7744         // the vertex shader, because most of the dynamic vertex animation cases
7745         // need actual vertex positions and normals
7746         //if (dynamicvertex)
7747         {
7748                 rsurface.batchvertex3f = NULL;
7749                 rsurface.batchvertex3f_vertexbuffer = NULL;
7750                 rsurface.batchvertex3f_bufferoffset = 0;
7751                 rsurface.batchsvector3f = NULL;
7752                 rsurface.batchsvector3f_vertexbuffer = NULL;
7753                 rsurface.batchsvector3f_bufferoffset = 0;
7754                 rsurface.batchtvector3f = NULL;
7755                 rsurface.batchtvector3f_vertexbuffer = NULL;
7756                 rsurface.batchtvector3f_bufferoffset = 0;
7757                 rsurface.batchnormal3f = NULL;
7758                 rsurface.batchnormal3f_vertexbuffer = NULL;
7759                 rsurface.batchnormal3f_bufferoffset = 0;
7760                 rsurface.batchlightmapcolor4f = NULL;
7761                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7762                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7763                 rsurface.batchtexcoordtexture2f = NULL;
7764                 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7765                 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7766                 rsurface.batchtexcoordlightmap2f = NULL;
7767                 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7768                 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7769                 rsurface.batchskeletalindex4ub = NULL;
7770                 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7771                 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7772                 rsurface.batchskeletalweight4ub = NULL;
7773                 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7774                 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7775                 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7776                 rsurface.batchelement3i_indexbuffer = NULL;
7777                 rsurface.batchelement3i_bufferoffset = 0;
7778                 rsurface.batchelement3s = NULL;
7779                 rsurface.batchelement3s_indexbuffer = NULL;
7780                 rsurface.batchelement3s_bufferoffset = 0;
7781                 rsurface.batchskeletaltransform3x4buffer = NULL;
7782                 rsurface.batchskeletaltransform3x4offset = 0;
7783                 rsurface.batchskeletaltransform3x4size = 0;
7784                 // we'll only be setting up certain arrays as needed
7785                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7786                         rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7787                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7788                         rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7789                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7790                 {
7791                         rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7792                         rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7793                 }
7794                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7795                         rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
7796                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7797                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7798                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7799                         rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7800                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7801                 {
7802                         rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7803                         rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7804                 }
7805                 numvertices = 0;
7806                 numtriangles = 0;
7807                 for (i = 0;i < texturenumsurfaces;i++)
7808                 {
7809                         surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
7810                         surfacenumvertices = texturesurfacelist[i]->num_vertices;
7811                         surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7812                         surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7813                         // copy only the data requested
7814                         if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
7815                         {
7816                                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7817                                 {
7818                                         if (rsurface.batchvertex3f)
7819                                                 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7820                                         else
7821                                                 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7822                                 }
7823                                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7824                                 {
7825                                         if (rsurface.modelnormal3f)
7826                                                 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7827                                         else
7828                                                 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7829                                 }
7830                                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7831                                 {
7832                                         if (rsurface.modelsvector3f)
7833                                         {
7834                                                 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7835                                                 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7836                                         }
7837                                         else
7838                                         {
7839                                                 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7840                                                 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7841                                         }
7842                                 }
7843                                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7844                                 {
7845                                         if (rsurface.modellightmapcolor4f)
7846                                                 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
7847                                         else
7848                                                 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
7849                                 }
7850                                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7851                                 {
7852                                         if (rsurface.modeltexcoordtexture2f)
7853                                                 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7854                                         else
7855                                                 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7856                                 }
7857                                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7858                                 {
7859                                         if (rsurface.modeltexcoordlightmap2f)
7860                                                 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7861                                         else
7862                                                 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7863                                 }
7864                                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7865                                 {
7866                                         if (rsurface.modelskeletalindex4ub)
7867                                         {
7868                                                 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7869                                                 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7870                                         }
7871                                         else
7872                                         {
7873                                                 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7874                                                 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7875                                                 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
7876                                                 for (j = 0;j < surfacenumvertices;j++)
7877                                                         ub[j*4] = 255;
7878                                         }
7879                                 }
7880                         }
7881                         RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
7882                         numvertices += surfacenumvertices;
7883                         numtriangles += surfacenumtriangles;
7884                 }
7885
7886                 // generate a 16bit index array as well if possible
7887                 // (in general, dynamic batches fit)
7888                 if (numvertices <= 65536)
7889                 {
7890                         rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7891                         for (i = 0;i < numtriangles*3;i++)
7892                                 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7893                 }
7894
7895                 // since we've copied everything, the batch now starts at 0
7896                 rsurface.batchfirstvertex = 0;
7897                 rsurface.batchnumvertices = batchnumvertices;
7898                 rsurface.batchfirsttriangle = 0;
7899                 rsurface.batchnumtriangles = batchnumtriangles;
7900         }
7901
7902         // apply skeletal animation that would have been done in the vertex shader
7903         if (rsurface.batchskeletaltransform3x4)
7904         {
7905                 const unsigned char *si;
7906                 const unsigned char *sw;
7907                 const float *t[4];
7908                 const float *b = rsurface.batchskeletaltransform3x4;
7909                 float *vp, *vs, *vt, *vn;
7910                 float w[4];
7911                 float m[3][4], n[3][4];
7912                 float tp[3], ts[3], tt[3], tn[3];
7913                 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
7914                 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
7915                 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
7916                 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
7917                 si = rsurface.batchskeletalindex4ub;
7918                 sw = rsurface.batchskeletalweight4ub;
7919                 vp = rsurface.batchvertex3f;
7920                 vs = rsurface.batchsvector3f;
7921                 vt = rsurface.batchtvector3f;
7922                 vn = rsurface.batchnormal3f;
7923                 memset(m[0], 0, sizeof(m));
7924                 memset(n[0], 0, sizeof(n));
7925                 for (i = 0;i < batchnumvertices;i++)
7926                 {
7927                         t[0] = b + si[0]*12;
7928                         if (sw[0] == 255)
7929                         {
7930                                 // common case - only one matrix
7931                                 m[0][0] = t[0][ 0];
7932                                 m[0][1] = t[0][ 1];
7933                                 m[0][2] = t[0][ 2];
7934                                 m[0][3] = t[0][ 3];
7935                                 m[1][0] = t[0][ 4];
7936                                 m[1][1] = t[0][ 5];
7937                                 m[1][2] = t[0][ 6];
7938                                 m[1][3] = t[0][ 7];
7939                                 m[2][0] = t[0][ 8];
7940                                 m[2][1] = t[0][ 9];
7941                                 m[2][2] = t[0][10];
7942                                 m[2][3] = t[0][11];
7943                         }
7944                         else if (sw[2] + sw[3])
7945                         {
7946                                 // blend 4 matrices
7947                                 t[1] = b + si[1]*12;
7948                                 t[2] = b + si[2]*12;
7949                                 t[3] = b + si[3]*12;
7950                                 w[0] = sw[0] * (1.0f / 255.0f);
7951                                 w[1] = sw[1] * (1.0f / 255.0f);
7952                                 w[2] = sw[2] * (1.0f / 255.0f);
7953                                 w[3] = sw[3] * (1.0f / 255.0f);
7954                                 // blend the matrices
7955                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
7956                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
7957                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
7958                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
7959                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
7960                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
7961                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
7962                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
7963                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
7964                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
7965                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
7966                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
7967                         }
7968                         else
7969                         {
7970                                 // blend 2 matrices
7971                                 t[1] = b + si[1]*12;
7972                                 w[0] = sw[0] * (1.0f / 255.0f);
7973                                 w[1] = sw[1] * (1.0f / 255.0f);
7974                                 // blend the matrices
7975                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
7976                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
7977                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
7978                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
7979                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
7980                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
7981                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
7982                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
7983                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
7984                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
7985                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
7986                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
7987                         }
7988                         si += 4;
7989                         sw += 4;
7990                         // modify the vertex
7991                         VectorCopy(vp, tp);
7992                         vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
7993                         vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
7994                         vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
7995                         vp += 3;
7996                         if (vn)
7997                         {
7998                                 // the normal transformation matrix is a set of cross products...
7999                                 CrossProduct(m[1], m[2], n[0]);
8000                                 CrossProduct(m[2], m[0], n[1]);
8001                                 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8002                                 VectorCopy(vn, tn);
8003                                 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8004                                 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8005                                 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8006                                 VectorNormalize(vn);
8007                                 vn += 3;
8008                                 if (vs)
8009                                 {
8010                                         VectorCopy(vs, ts);
8011                                         vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8012                                         vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8013                                         vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8014                                         VectorNormalize(vs);
8015                                         vs += 3;
8016                                         VectorCopy(vt, tt);
8017                                         vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8018                                         vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8019                                         vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8020                                         VectorNormalize(vt);
8021                                         vt += 3;
8022                                 }
8023                         }
8024                 }
8025                 rsurface.batchskeletaltransform3x4 = NULL;
8026                 rsurface.batchskeletalnumtransforms = 0;
8027         }
8028
8029         // q1bsp surfaces rendered in vertex color mode have to have colors
8030         // calculated based on lightstyles
8031         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
8032         {
8033                 // generate color arrays for the surfaces in this list
8034                 int c[4];
8035                 int scale;
8036                 int size3;
8037                 const int *offsets;
8038                 const unsigned char *lm;
8039                 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8040                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8041                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8042                 numvertices = 0;
8043                 for (i = 0;i < texturenumsurfaces;i++)
8044                 {
8045                         surface = texturesurfacelist[i];
8046                         offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8047                         surfacenumvertices = surface->num_vertices;
8048                         if (surface->lightmapinfo->samples)
8049                         {
8050                                 for (j = 0;j < surfacenumvertices;j++)
8051                                 {
8052                                         lm = surface->lightmapinfo->samples + offsets[j];
8053                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8054                                         VectorScale(lm, scale, c);
8055                                         if (surface->lightmapinfo->styles[1] != 255)
8056                                         {
8057                                                 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8058                                                 lm += size3;
8059                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8060                                                 VectorMA(c, scale, lm, c);
8061                                                 if (surface->lightmapinfo->styles[2] != 255)
8062                                                 {
8063                                                         lm += size3;
8064                                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8065                                                         VectorMA(c, scale, lm, c);
8066                                                         if (surface->lightmapinfo->styles[3] != 255)
8067                                                         {
8068                                                                 lm += size3;
8069                                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8070                                                                 VectorMA(c, scale, lm, c);
8071                                                         }
8072                                                 }
8073                                         }
8074                                         c[0] >>= 7;
8075                                         c[1] >>= 7;
8076                                         c[2] >>= 7;
8077                                         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);
8078                                         numvertices++;
8079                                 }
8080                         }
8081                         else
8082                         {
8083                                 for (j = 0;j < surfacenumvertices;j++)
8084                                 {
8085                                         Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8086                                         numvertices++;
8087                                 }
8088                         }
8089                 }
8090         }
8091
8092         // if vertices are deformed (sprite flares and things in maps, possibly
8093         // water waves, bulges and other deformations), modify the copied vertices
8094         // in place
8095         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8096         {
8097                 float scale;
8098                 switch (deform->deform)
8099                 {
8100                 default:
8101                 case Q3DEFORM_PROJECTIONSHADOW:
8102                 case Q3DEFORM_TEXT0:
8103                 case Q3DEFORM_TEXT1:
8104                 case Q3DEFORM_TEXT2:
8105                 case Q3DEFORM_TEXT3:
8106                 case Q3DEFORM_TEXT4:
8107                 case Q3DEFORM_TEXT5:
8108                 case Q3DEFORM_TEXT6:
8109                 case Q3DEFORM_TEXT7:
8110                 case Q3DEFORM_NONE:
8111                         break;
8112                 case Q3DEFORM_AUTOSPRITE:
8113                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8114                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8115                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8116                         VectorNormalize(newforward);
8117                         VectorNormalize(newright);
8118                         VectorNormalize(newup);
8119 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8120 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8121 //                      rsurface.batchvertex3f_bufferoffset = 0;
8122 //                      rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8123 //                      rsurface.batchsvector3f_vertexbuffer = NULL;
8124 //                      rsurface.batchsvector3f_bufferoffset = 0;
8125 //                      rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8126 //                      rsurface.batchtvector3f_vertexbuffer = NULL;
8127 //                      rsurface.batchtvector3f_bufferoffset = 0;
8128 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8129 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8130 //                      rsurface.batchnormal3f_bufferoffset = 0;
8131                         // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8132                         if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8133                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8134                         if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8135                                 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);
8136                         // a single autosprite surface can contain multiple sprites...
8137                         for (j = 0;j < batchnumvertices - 3;j += 4)
8138                         {
8139                                 VectorClear(center);
8140                                 for (i = 0;i < 4;i++)
8141                                         VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8142                                 VectorScale(center, 0.25f, center);
8143                                 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8144                                 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8145                                 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8146                                 for (i = 0;i < 4;i++)
8147                                 {
8148                                         VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8149                                         VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8150                                 }
8151                         }
8152                         // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8153                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8154                         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);
8155                         break;
8156                 case Q3DEFORM_AUTOSPRITE2:
8157                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8158                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8159                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8160                         VectorNormalize(newforward);
8161                         VectorNormalize(newright);
8162                         VectorNormalize(newup);
8163 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8164 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8165 //                      rsurface.batchvertex3f_bufferoffset = 0;
8166                         {
8167                                 const float *v1, *v2;
8168                                 vec3_t start, end;
8169                                 float f, l;
8170                                 struct
8171                                 {
8172                                         float length2;
8173                                         const float *v1;
8174                                         const float *v2;
8175                                 }
8176                                 shortest[2];
8177                                 memset(shortest, 0, sizeof(shortest));
8178                                 // a single autosprite surface can contain multiple sprites...
8179                                 for (j = 0;j < batchnumvertices - 3;j += 4)
8180                                 {
8181                                         VectorClear(center);
8182                                         for (i = 0;i < 4;i++)
8183                                                 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8184                                         VectorScale(center, 0.25f, center);
8185                                         // find the two shortest edges, then use them to define the
8186                                         // axis vectors for rotating around the central axis
8187                                         for (i = 0;i < 6;i++)
8188                                         {
8189                                                 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8190                                                 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8191                                                 l = VectorDistance2(v1, v2);
8192                                                 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8193                                                 if (v1[2] != v2[2])
8194                                                         l += (1.0f / 1024.0f);
8195                                                 if (shortest[0].length2 > l || i == 0)
8196                                                 {
8197                                                         shortest[1] = shortest[0];
8198                                                         shortest[0].length2 = l;
8199                                                         shortest[0].v1 = v1;
8200                                                         shortest[0].v2 = v2;
8201                                                 }
8202                                                 else if (shortest[1].length2 > l || i == 1)
8203                                                 {
8204                                                         shortest[1].length2 = l;
8205                                                         shortest[1].v1 = v1;
8206                                                         shortest[1].v2 = v2;
8207                                                 }
8208                                         }
8209                                         VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8210                                         VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8211                                         // this calculates the right vector from the shortest edge
8212                                         // and the up vector from the edge midpoints
8213                                         VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8214                                         VectorNormalize(right);
8215                                         VectorSubtract(end, start, up);
8216                                         VectorNormalize(up);
8217                                         // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8218                                         VectorSubtract(rsurface.localvieworigin, center, forward);
8219                                         //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8220                                         VectorNegate(forward, forward);
8221                                         VectorReflect(forward, 0, up, forward);
8222                                         VectorNormalize(forward);
8223                                         CrossProduct(up, forward, newright);
8224                                         VectorNormalize(newright);
8225                                         // rotate the quad around the up axis vector, this is made
8226                                         // especially easy by the fact we know the quad is flat,
8227                                         // so we only have to subtract the center position and
8228                                         // measure distance along the right vector, and then
8229                                         // multiply that by the newright vector and add back the
8230                                         // center position
8231                                         // we also need to subtract the old position to undo the
8232                                         // displacement from the center, which we do with a
8233                                         // DotProduct, the subtraction/addition of center is also
8234                                         // optimized into DotProducts here
8235                                         l = DotProduct(right, center);
8236                                         for (i = 0;i < 4;i++)
8237                                         {
8238                                                 v1 = rsurface.batchvertex3f + 3*(j+i);
8239                                                 f = DotProduct(right, v1) - l;
8240                                                 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8241                                         }
8242                                 }
8243                         }
8244                         if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8245                         {
8246 //                              rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8247 //                              rsurface.batchnormal3f_vertexbuffer = NULL;
8248 //                              rsurface.batchnormal3f_bufferoffset = 0;
8249                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8250                         }
8251                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8252                         {
8253 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8254 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8255 //                              rsurface.batchsvector3f_bufferoffset = 0;
8256 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8257 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8258 //                              rsurface.batchtvector3f_bufferoffset = 0;
8259                                 Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchsvector3f, rsurface.batchtvector3f, r_smoothnormals_areaweighting.integer != 0);
8260                         }
8261                         break;
8262                 case Q3DEFORM_NORMAL:
8263                         // deform the normals to make reflections wavey
8264                         rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8265                         rsurface.batchnormal3f_vertexbuffer = NULL;
8266                         rsurface.batchnormal3f_bufferoffset = 0;
8267                         for (j = 0;j < batchnumvertices;j++)
8268                         {
8269                                 float vertex[3];
8270                                 float *normal = rsurface.batchnormal3f + 3*j;
8271                                 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8272                                 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8273                                 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8274                                 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8275                                 VectorNormalize(normal);
8276                         }
8277                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8278                         {
8279 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8280 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8281 //                              rsurface.batchsvector3f_bufferoffset = 0;
8282 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8283 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8284 //                              rsurface.batchtvector3f_bufferoffset = 0;
8285                                 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);
8286                         }
8287                         break;
8288                 case Q3DEFORM_WAVE:
8289                         // deform vertex array to make wavey water and flags and such
8290                         waveparms[0] = deform->waveparms[0];
8291                         waveparms[1] = deform->waveparms[1];
8292                         waveparms[2] = deform->waveparms[2];
8293                         waveparms[3] = deform->waveparms[3];
8294                         if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8295                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8296                         // this is how a divisor of vertex influence on deformation
8297                         animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8298                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8299 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8300 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8301 //                      rsurface.batchvertex3f_bufferoffset = 0;
8302 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8303 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8304 //                      rsurface.batchnormal3f_bufferoffset = 0;
8305                         for (j = 0;j < batchnumvertices;j++)
8306                         {
8307                                 // if the wavefunc depends on time, evaluate it per-vertex
8308                                 if (waveparms[3])
8309                                 {
8310                                         waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8311                                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8312                                 }
8313                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8314                         }
8315                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8316                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8317                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8318                         {
8319 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8320 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8321 //                              rsurface.batchsvector3f_bufferoffset = 0;
8322 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8323 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8324 //                              rsurface.batchtvector3f_bufferoffset = 0;
8325                                 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);
8326                         }
8327                         break;
8328                 case Q3DEFORM_BULGE:
8329                         // deform vertex array to make the surface have moving bulges
8330 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8331 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8332 //                      rsurface.batchvertex3f_bufferoffset = 0;
8333 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8334 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8335 //                      rsurface.batchnormal3f_bufferoffset = 0;
8336                         for (j = 0;j < batchnumvertices;j++)
8337                         {
8338                                 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8339                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8340                         }
8341                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8342                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8343                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8344                         {
8345 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8346 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8347 //                              rsurface.batchsvector3f_bufferoffset = 0;
8348 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8349 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8350 //                              rsurface.batchtvector3f_bufferoffset = 0;
8351                                 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);
8352                         }
8353                         break;
8354                 case Q3DEFORM_MOVE:
8355                         // deform vertex array
8356                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8357                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8358                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8359                         VectorScale(deform->parms, scale, waveparms);
8360 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8361 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8362 //                      rsurface.batchvertex3f_bufferoffset = 0;
8363                         for (j = 0;j < batchnumvertices;j++)
8364                                 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8365                         break;
8366                 }
8367         }
8368
8369         if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8370         {
8371         // generate texcoords based on the chosen texcoord source
8372                 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8373                 {
8374                 default:
8375                 case Q3TCGEN_TEXTURE:
8376                         break;
8377                 case Q3TCGEN_LIGHTMAP:
8378         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8379         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8380         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8381                         if (rsurface.batchtexcoordlightmap2f)
8382                                 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8383                         break;
8384                 case Q3TCGEN_VECTOR:
8385         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8386         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8387         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8388                         for (j = 0;j < batchnumvertices;j++)
8389                         {
8390                                 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8391                                 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8392                         }
8393                         break;
8394                 case Q3TCGEN_ENVIRONMENT:
8395                         // make environment reflections using a spheremap
8396                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8397                         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8398                         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8399                         for (j = 0;j < batchnumvertices;j++)
8400                         {
8401                                 // identical to Q3A's method, but executed in worldspace so
8402                                 // carried models can be shiny too
8403
8404                                 float viewer[3], d, reflected[3], worldreflected[3];
8405
8406                                 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8407                                 // VectorNormalize(viewer);
8408
8409                                 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8410
8411                                 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8412                                 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8413                                 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8414                                 // note: this is proportinal to viewer, so we can normalize later
8415
8416                                 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8417                                 VectorNormalize(worldreflected);
8418
8419                                 // note: this sphere map only uses world x and z!
8420                                 // so positive and negative y will LOOK THE SAME.
8421                                 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8422                                 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8423                         }
8424                         break;
8425                 }
8426                 // the only tcmod that needs software vertex processing is turbulent, so
8427                 // check for it here and apply the changes if needed
8428                 // and we only support that as the first one
8429                 // (handling a mixture of turbulent and other tcmods would be problematic
8430                 //  without punting it entirely to a software path)
8431                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8432                 {
8433                         amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8434                         animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8435         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8436         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8437         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8438                         for (j = 0;j < batchnumvertices;j++)
8439                         {
8440                                 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);
8441                                 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8442                         }
8443                 }
8444         }
8445 }
8446
8447 void RSurf_DrawBatch(void)
8448 {
8449         // sometimes a zero triangle surface (usually a degenerate patch) makes it
8450         // through the pipeline, killing it earlier in the pipeline would have
8451         // per-surface overhead rather than per-batch overhead, so it's best to
8452         // reject it here, before it hits glDraw.
8453         if (rsurface.batchnumtriangles == 0)
8454                 return;
8455 #if 0
8456         // batch debugging code
8457         if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8458         {
8459                 int i;
8460                 int j;
8461                 int c;
8462                 const int *e;
8463                 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8464                 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8465                 {
8466                         c = e[i];
8467                         for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8468                         {
8469                                 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8470                                 {
8471                                         if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8472                                                 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);
8473                                         break;
8474                                 }
8475                         }
8476                 }
8477         }
8478 #endif
8479         if (rsurface.batchmultidraw)
8480         {
8481                 // issue multiple draws rather than copying index data
8482                 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8483                 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8484                 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8485                 for (i = 0;i < numsurfaces;)
8486                 {
8487                         // combine consecutive surfaces as one draw
8488                         for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8489                                 if (surfacelist[j] != surfacelist[k] + 1)
8490                                         break;
8491                         firstvertex = surfacelist[i]->num_firstvertex;
8492                         endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8493                         firsttriangle = surfacelist[i]->num_firsttriangle;
8494                         endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8495                         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);
8496                         i = j;
8497                 }
8498         }
8499         else
8500         {
8501                 // there is only one consecutive run of index data (may have been combined)
8502                 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);
8503         }
8504 }
8505
8506 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8507 {
8508         // pick the closest matching water plane
8509         int planeindex, vertexindex, bestplaneindex = -1;
8510         float d, bestd;
8511         vec3_t vert;
8512         const float *v;
8513         r_waterstate_waterplane_t *p;
8514         qboolean prepared = false;
8515         bestd = 0;
8516         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8517         {
8518                 if(p->camera_entity != rsurface.texture->camera_entity)
8519                         continue;
8520                 d = 0;
8521                 if(!prepared)
8522                 {
8523                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8524                         prepared = true;
8525                         if(rsurface.batchnumvertices == 0)
8526                                 break;
8527                 }
8528                 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8529                 {
8530                         Matrix4x4_Transform(&rsurface.matrix, v, vert);
8531                         d += fabs(PlaneDiff(vert, &p->plane));
8532                 }
8533                 if (bestd > d || bestplaneindex < 0)
8534                 {
8535                         bestd = d;
8536                         bestplaneindex = planeindex;
8537                 }
8538         }
8539         return bestplaneindex;
8540         // NOTE: this MAY return a totally unrelated water plane; we can ignore
8541         // this situation though, as it might be better to render single larger
8542         // batches with useless stuff (backface culled for example) than to
8543         // render multiple smaller batches
8544 }
8545
8546 void RSurf_SetupDepthAndCulling(void)
8547 {
8548         // submodels are biased to avoid z-fighting with world surfaces that they
8549         // may be exactly overlapping (avoids z-fighting artifacts on certain
8550         // doors and things in Quake maps)
8551         GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8552         GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8553         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8554         GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8555 }
8556
8557 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8558 {
8559         int i, j;
8560         // transparent sky would be ridiculous
8561         if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8562                 return;
8563         R_SetupShader_Generic_NoTexture(false, false);
8564         skyrenderlater = true;
8565         RSurf_SetupDepthAndCulling();
8566         GL_DepthMask(true);
8567
8568         // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8569         if (r_sky_scissor.integer)
8570         {
8571                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8572                 for (i = 0; i < texturenumsurfaces; i++)
8573                 {
8574                         const msurface_t *surf = texturesurfacelist[i];
8575                         const float *v;
8576                         float p[3];
8577                         float mins[3], maxs[3];
8578                         int scissor[4];
8579                         for (j = 0, v = rsurface.batchvertex3f + 3 * surf->num_firstvertex; j < surf->num_vertices; j++, v += 3)
8580                         {
8581                                 Matrix4x4_Transform(&rsurface.matrix, v, p);
8582                                 if (j > 0)
8583                                 {
8584                                         if (mins[0] > p[0]) mins[0] = p[0];
8585                                         if (mins[1] > p[1]) mins[1] = p[1];
8586                                         if (mins[2] > p[2]) mins[2] = p[2];
8587                                         if (maxs[0] < p[0]) maxs[0] = p[0];
8588                                         if (maxs[1] < p[1]) maxs[1] = p[1];
8589                                         if (maxs[2] < p[2]) maxs[2] = p[2];
8590                                 }
8591                                 else
8592                                 {
8593                                         VectorCopy(p, mins);
8594                                         VectorCopy(p, maxs);
8595                                 }
8596                         }
8597                         if (!R_ScissorForBBox(mins, maxs, scissor))
8598                         {
8599                                 if (skyscissor[2])
8600                                 {
8601                                         if (skyscissor[0] > scissor[0])
8602                                         {
8603                                                 skyscissor[2] += skyscissor[0] - scissor[0];
8604                                                 skyscissor[0] = scissor[0];
8605                                         }
8606                                         if (skyscissor[1] > scissor[1])
8607                                         {
8608                                                 skyscissor[3] += skyscissor[1] - scissor[1];
8609                                                 skyscissor[1] = scissor[1];
8610                                         }
8611                                         if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8612                                                 skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8613                                         if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8614                                                 skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8615                                 }
8616                                 else
8617                                         Vector4Copy(scissor, skyscissor);
8618                         }
8619                 }
8620         }
8621
8622         // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8623         // skymasking on them, and Quake3 never did sky masking (unlike
8624         // software Quake and software Quake2), so disable the sky masking
8625         // in Quake3 maps as it causes problems with q3map2 sky tricks,
8626         // and skymasking also looks very bad when noclipping outside the
8627         // level, so don't use it then either.
8628         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)
8629         {
8630                 R_Mesh_ResetTextureState();
8631                 if (skyrendermasked)
8632                 {
8633                         R_SetupShader_DepthOrShadow(false, false, false);
8634                         // depth-only (masking)
8635                         GL_ColorMask(0, 0, 0, 0);
8636                         // just to make sure that braindead drivers don't draw
8637                         // anything despite that colormask...
8638                         GL_BlendFunc(GL_ZERO, GL_ONE);
8639                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8640                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8641                 }
8642                 else
8643                 {
8644                         R_SetupShader_Generic_NoTexture(false, false);
8645                         // fog sky
8646                         GL_BlendFunc(GL_ONE, GL_ZERO);
8647                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8648                         GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
8649                         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
8650                 }
8651                 RSurf_DrawBatch();
8652                 if (skyrendermasked)
8653                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8654         }
8655         R_Mesh_ResetTextureState();
8656         GL_Color(1, 1, 1, 1);
8657 }
8658
8659 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
8660 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
8661 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass, qboolean ui)
8662 {
8663         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
8664                 return;
8665         if (prepass)
8666         {
8667                 // render screenspace normalmap to texture
8668                 GL_DepthMask(true);
8669                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false);
8670                 RSurf_DrawBatch();
8671                 return;
8672         }
8673
8674         // bind lightmap texture
8675
8676         // water/refraction/reflection/camera surfaces have to be handled specially
8677         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
8678         {
8679                 int start, end, startplaneindex;
8680                 for (start = 0;start < texturenumsurfaces;start = end)
8681                 {
8682                         startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
8683                         if(startplaneindex < 0)
8684                         {
8685                                 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
8686                                 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
8687                                 end = start + 1;
8688                                 continue;
8689                         }
8690                         for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
8691                                 ;
8692                         // now that we have a batch using the same planeindex, render it
8693                         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
8694                         {
8695                                 // render water or distortion background
8696                                 GL_DepthMask(true);
8697                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8698                                 RSurf_DrawBatch();
8699                                 // blend surface on top
8700                                 GL_DepthMask(false);
8701                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false);
8702                                 RSurf_DrawBatch();
8703                         }
8704                         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
8705                         {
8706                                 // render surface with reflection texture as input
8707                                 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8708                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8709                                 RSurf_DrawBatch();
8710                         }
8711                 }
8712                 return;
8713         }
8714
8715         // render surface batch normally
8716         GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8717         R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0 || ui);
8718         RSurf_DrawBatch();
8719 }
8720
8721 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
8722 {
8723         int vi;
8724         int j;
8725         int texturesurfaceindex;
8726         int k;
8727         const msurface_t *surface;
8728         float surfacecolor4f[4];
8729
8730 //      R_Mesh_ResetTextureState();
8731         R_SetupShader_Generic_NoTexture(false, false);
8732
8733         GL_BlendFunc(GL_ONE, GL_ZERO);
8734         GL_DepthMask(writedepth);
8735
8736         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
8737         vi = 0;
8738         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8739         {
8740                 surface = texturesurfacelist[texturesurfaceindex];
8741                 k = (int)(((size_t)surface) / sizeof(msurface_t));
8742                 Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
8743                 for (j = 0;j < surface->num_vertices;j++)
8744                 {
8745                         Vector4Copy(surfacecolor4f, rsurface.batchlightmapcolor4f + 4 * vi);
8746                         vi++;
8747                 }
8748         }
8749         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchlightmapcolor4f, rsurface.batchtexcoordtexture2f);
8750         RSurf_DrawBatch();
8751 }
8752
8753 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass, qboolean ui)
8754 {
8755         CHECKGLERROR
8756         RSurf_SetupDepthAndCulling();
8757         if (r_showsurfaces.integer && r_refdef.view.showdebug)
8758         {
8759                 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
8760                 return;
8761         }
8762         switch (vid.renderpath)
8763         {
8764         case RENDERPATH_GL32:
8765         case RENDERPATH_GLES2:
8766                 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8767                 break;
8768         }
8769         CHECKGLERROR
8770 }
8771
8772 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
8773 {
8774         int i, j;
8775         int texturenumsurfaces, endsurface;
8776         texture_t *texture;
8777         const msurface_t *surface;
8778         const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
8779
8780         RSurf_ActiveModelEntity(ent, true, true, false);
8781
8782         if (r_transparentdepthmasking.integer)
8783         {
8784                 qboolean setup = false;
8785                 for (i = 0;i < numsurfaces;i = j)
8786                 {
8787                         j = i + 1;
8788                         surface = rsurface.modelsurfaces + surfacelist[i];
8789                         texture = surface->texture;
8790                         rsurface.texture = R_GetCurrentTexture(texture);
8791                         rsurface.lightmaptexture = NULL;
8792                         rsurface.deluxemaptexture = NULL;
8793                         rsurface.uselightmaptexture = false;
8794                         // scan ahead until we find a different texture
8795                         endsurface = min(i + 1024, numsurfaces);
8796                         texturenumsurfaces = 0;
8797                         texturesurfacelist[texturenumsurfaces++] = surface;
8798                         for (;j < endsurface;j++)
8799                         {
8800                                 surface = rsurface.modelsurfaces + surfacelist[j];
8801                                 if (texture != surface->texture)
8802                                         break;
8803                                 texturesurfacelist[texturenumsurfaces++] = surface;
8804                         }
8805                         if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
8806                                 continue;
8807                         // render the range of surfaces as depth
8808                         if (!setup)
8809                         {
8810                                 setup = true;
8811                                 GL_ColorMask(0,0,0,0);
8812                                 GL_Color(1,1,1,1);
8813                                 GL_DepthTest(true);
8814                                 GL_BlendFunc(GL_ONE, GL_ZERO);
8815                                 GL_DepthMask(true);
8816 //                              R_Mesh_ResetTextureState();
8817                         }
8818                         RSurf_SetupDepthAndCulling();
8819                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8820                         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8821                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8822                         RSurf_DrawBatch();
8823                 }
8824                 if (setup)
8825                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8826         }
8827
8828         for (i = 0;i < numsurfaces;i = j)
8829         {
8830                 j = i + 1;
8831                 surface = rsurface.modelsurfaces + surfacelist[i];
8832                 texture = surface->texture;
8833                 rsurface.texture = R_GetCurrentTexture(texture);
8834                 // scan ahead until we find a different texture
8835                 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
8836                 texturenumsurfaces = 0;
8837                 texturesurfacelist[texturenumsurfaces++] = surface;
8838                         rsurface.lightmaptexture = surface->lightmaptexture;
8839                         rsurface.deluxemaptexture = surface->deluxemaptexture;
8840                         rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
8841                         for (;j < endsurface;j++)
8842                         {
8843                                 surface = rsurface.modelsurfaces + surfacelist[j];
8844                                 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
8845                                         break;
8846                                 texturesurfacelist[texturenumsurfaces++] = surface;
8847                         }
8848                 // render the range of surfaces
8849                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false, false);
8850         }
8851         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
8852 }
8853
8854 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8855 {
8856         // transparent surfaces get pushed off into the transparent queue
8857         int surfacelistindex;
8858         const msurface_t *surface;
8859         vec3_t tempcenter, center;
8860         for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
8861         {
8862                 surface = texturesurfacelist[surfacelistindex];
8863                 if (r_transparent_sortsurfacesbynearest.integer)
8864                 {
8865                         tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
8866                         tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
8867                         tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
8868                 }
8869                 else
8870                 {
8871                         tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
8872                         tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
8873                         tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
8874                 }
8875                 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
8876                 if (rsurface.entity->transparent_offset) // transparent offset
8877                 {
8878                         center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
8879                         center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
8880                         center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
8881                 }
8882                 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);
8883         }
8884 }
8885
8886 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8887 {
8888         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
8889                 return;
8890         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
8891                 return;
8892         RSurf_SetupDepthAndCulling();
8893         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8894         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8895         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8896         RSurf_DrawBatch();
8897 }
8898
8899 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass, qboolean ui)
8900 {
8901         CHECKGLERROR
8902         if (ui)
8903                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8904         else if (depthonly)
8905                 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
8906         else if (prepass)
8907         {
8908                 if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
8909                         return;
8910                 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8911                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
8912                 else
8913                         R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8914         }
8915         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
8916                 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
8917         else if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
8918                 return;
8919         else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
8920         {
8921                 // in the deferred case, transparent surfaces were queued during prepass
8922                 if (!r_shadow_usingdeferredprepass)
8923                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
8924         }
8925         else
8926         {
8927                 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
8928                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass, ui);
8929         }
8930         CHECKGLERROR
8931 }
8932
8933 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass, qboolean ui)
8934 {
8935         int i, j;
8936         texture_t *texture;
8937         R_FrameData_SetMark();
8938         // break the surface list down into batches by texture and use of lightmapping
8939         for (i = 0;i < numsurfaces;i = j)
8940         {
8941                 j = i + 1;
8942                 // texture is the base texture pointer, rsurface.texture is the
8943                 // current frame/skin the texture is directing us to use (for example
8944                 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
8945                 // use skin 1 instead)
8946                 texture = surfacelist[i]->texture;
8947                 rsurface.texture = R_GetCurrentTexture(texture);
8948                 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
8949                 {
8950                         // if this texture is not the kind we want, skip ahead to the next one
8951                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
8952                                 ;
8953                         continue;
8954                 }
8955                 if(depthonly || prepass)
8956                 {
8957                         rsurface.lightmaptexture = NULL;
8958                         rsurface.deluxemaptexture = NULL;
8959                         rsurface.uselightmaptexture = false;
8960                         // simply scan ahead until we find a different texture or lightmap state
8961                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
8962                                 ;
8963                 }
8964                 else
8965                 {
8966                         rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
8967                         rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
8968                         rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
8969                         // simply scan ahead until we find a different texture or lightmap state
8970                         for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
8971                                 ;
8972                 }
8973                 // render the range of surfaces
8974                 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass, ui);
8975         }
8976         R_FrameData_ReturnToMark();
8977 }
8978
8979 float locboxvertex3f[6*4*3] =
8980 {
8981         1,0,1, 1,0,0, 1,1,0, 1,1,1,
8982         0,1,1, 0,1,0, 0,0,0, 0,0,1,
8983         1,1,1, 1,1,0, 0,1,0, 0,1,1,
8984         0,0,1, 0,0,0, 1,0,0, 1,0,1,
8985         0,0,1, 1,0,1, 1,1,1, 0,1,1,
8986         1,0,0, 0,0,0, 0,1,0, 1,1,0
8987 };
8988
8989 unsigned short locboxelements[6*2*3] =
8990 {
8991          0, 1, 2, 0, 2, 3,
8992          4, 5, 6, 4, 6, 7,
8993          8, 9,10, 8,10,11,
8994         12,13,14, 12,14,15,
8995         16,17,18, 16,18,19,
8996         20,21,22, 20,22,23
8997 };
8998
8999 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9000 {
9001         int i, j;
9002         cl_locnode_t *loc = (cl_locnode_t *)ent;
9003         vec3_t mins, size;
9004         float vertex3f[6*4*3];
9005         CHECKGLERROR
9006         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9007         GL_DepthMask(false);
9008         GL_DepthRange(0, 1);
9009         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9010         GL_DepthTest(true);
9011         GL_CullFace(GL_NONE);
9012         R_EntityMatrix(&identitymatrix);
9013
9014 //      R_Mesh_ResetTextureState();
9015
9016         i = surfacelist[0];
9017         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9018                          ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9019                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9020                         surfacelist[0] < 0 ? 0.5f : 0.125f);
9021
9022         if (VectorCompare(loc->mins, loc->maxs))
9023         {
9024                 VectorSet(size, 2, 2, 2);
9025                 VectorMA(loc->mins, -0.5f, size, mins);
9026         }
9027         else
9028         {
9029                 VectorCopy(loc->mins, mins);
9030                 VectorSubtract(loc->maxs, loc->mins, size);
9031         }
9032
9033         for (i = 0;i < 6*4*3;)
9034                 for (j = 0;j < 3;j++, i++)
9035                         vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9036
9037         R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9038         R_SetupShader_Generic_NoTexture(false, false);
9039         R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9040 }
9041
9042 void R_DrawLocs(void)
9043 {
9044         int index;
9045         cl_locnode_t *loc, *nearestloc;
9046         vec3_t center;
9047         nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9048         for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9049         {
9050                 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9051                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9052         }
9053 }
9054
9055 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9056 {
9057         if (decalsystem->decals)
9058                 Mem_Free(decalsystem->decals);
9059         memset(decalsystem, 0, sizeof(*decalsystem));
9060 }
9061
9062 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)
9063 {
9064         tridecal_t *decal;
9065         tridecal_t *decals;
9066         int i;
9067
9068         // expand or initialize the system
9069         if (decalsystem->maxdecals <= decalsystem->numdecals)
9070         {
9071                 decalsystem_t old = *decalsystem;
9072                 qboolean useshortelements;
9073                 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9074                 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9075                 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)));
9076                 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9077                 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9078                 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9079                 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9080                 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9081                 if (decalsystem->numdecals)
9082                         memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9083                 if (old.decals)
9084                         Mem_Free(old.decals);
9085                 for (i = 0;i < decalsystem->maxdecals*3;i++)
9086                         decalsystem->element3i[i] = i;
9087                 if (useshortelements)
9088                         for (i = 0;i < decalsystem->maxdecals*3;i++)
9089                                 decalsystem->element3s[i] = i;
9090         }
9091
9092         // grab a decal and search for another free slot for the next one
9093         decals = decalsystem->decals;
9094         decal = decalsystem->decals + (i = decalsystem->freedecal++);
9095         for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9096                 ;
9097         decalsystem->freedecal = i;
9098         if (decalsystem->numdecals <= i)
9099                 decalsystem->numdecals = i + 1;
9100
9101         // initialize the decal
9102         decal->lived = 0;
9103         decal->triangleindex = triangleindex;
9104         decal->surfaceindex = surfaceindex;
9105         decal->decalsequence = decalsequence;
9106         decal->color4f[0][0] = c0[0];
9107         decal->color4f[0][1] = c0[1];
9108         decal->color4f[0][2] = c0[2];
9109         decal->color4f[0][3] = 1;
9110         decal->color4f[1][0] = c1[0];
9111         decal->color4f[1][1] = c1[1];
9112         decal->color4f[1][2] = c1[2];
9113         decal->color4f[1][3] = 1;
9114         decal->color4f[2][0] = c2[0];
9115         decal->color4f[2][1] = c2[1];
9116         decal->color4f[2][2] = c2[2];
9117         decal->color4f[2][3] = 1;
9118         decal->vertex3f[0][0] = v0[0];
9119         decal->vertex3f[0][1] = v0[1];
9120         decal->vertex3f[0][2] = v0[2];
9121         decal->vertex3f[1][0] = v1[0];
9122         decal->vertex3f[1][1] = v1[1];
9123         decal->vertex3f[1][2] = v1[2];
9124         decal->vertex3f[2][0] = v2[0];
9125         decal->vertex3f[2][1] = v2[1];
9126         decal->vertex3f[2][2] = v2[2];
9127         decal->texcoord2f[0][0] = t0[0];
9128         decal->texcoord2f[0][1] = t0[1];
9129         decal->texcoord2f[1][0] = t1[0];
9130         decal->texcoord2f[1][1] = t1[1];
9131         decal->texcoord2f[2][0] = t2[0];
9132         decal->texcoord2f[2][1] = t2[1];
9133         TriangleNormal(v0, v1, v2, decal->plane);
9134         VectorNormalize(decal->plane);
9135         decal->plane[3] = DotProduct(v0, decal->plane);
9136 }
9137
9138 extern cvar_t cl_decals_bias;
9139 extern cvar_t cl_decals_models;
9140 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9141 // baseparms, parms, temps
9142 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)
9143 {
9144         int cornerindex;
9145         int index;
9146         float v[9][3];
9147         const float *vertex3f;
9148         const float *normal3f;
9149         int numpoints;
9150         float points[2][9][3];
9151         float temp[3];
9152         float tc[9][2];
9153         float f;
9154         float c[9][4];
9155         const int *e;
9156
9157         e = rsurface.modelelement3i + 3*triangleindex;
9158
9159         vertex3f = rsurface.modelvertex3f;
9160         normal3f = rsurface.modelnormal3f;
9161
9162         if (normal3f)
9163         {
9164                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9165                 {
9166                         index = 3*e[cornerindex];
9167                         VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9168                 }
9169         }
9170         else
9171         {
9172                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9173                 {
9174                         index = 3*e[cornerindex];
9175                         VectorCopy(vertex3f + index, v[cornerindex]);
9176                 }
9177         }
9178
9179         // cull backfaces
9180         //TriangleNormal(v[0], v[1], v[2], normal);
9181         //if (DotProduct(normal, localnormal) < 0.0f)
9182         //      continue;
9183         // clip by each of the box planes formed from the projection matrix
9184         // if anything survives, we emit the decal
9185         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]);
9186         if (numpoints < 3)
9187                 return;
9188         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]);
9189         if (numpoints < 3)
9190                 return;
9191         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]);
9192         if (numpoints < 3)
9193                 return;
9194         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]);
9195         if (numpoints < 3)
9196                 return;
9197         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]);
9198         if (numpoints < 3)
9199                 return;
9200         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]);
9201         if (numpoints < 3)
9202                 return;
9203         // some part of the triangle survived, so we have to accept it...
9204         if (dynamic)
9205         {
9206                 // dynamic always uses the original triangle
9207                 numpoints = 3;
9208                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9209                 {
9210                         index = 3*e[cornerindex];
9211                         VectorCopy(vertex3f + index, v[cornerindex]);
9212                 }
9213         }
9214         for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9215         {
9216                 // convert vertex positions to texcoords
9217                 Matrix4x4_Transform(projection, v[cornerindex], temp);
9218                 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9219                 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9220                 // calculate distance fade from the projection origin
9221                 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9222                 f = bound(0.0f, f, 1.0f);
9223                 c[cornerindex][0] = r * f;
9224                 c[cornerindex][1] = g * f;
9225                 c[cornerindex][2] = b * f;
9226                 c[cornerindex][3] = 1.0f;
9227                 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9228         }
9229         if (dynamic)
9230                 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);
9231         else
9232                 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9233                         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);
9234 }
9235 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)
9236 {
9237         matrix4x4_t projection;
9238         decalsystem_t *decalsystem;
9239         qboolean dynamic;
9240         dp_model_t *model;
9241         const msurface_t *surface;
9242         const msurface_t *surfaces;
9243         const int *surfacelist;
9244         const texture_t *texture;
9245         int numtriangles;
9246         int numsurfacelist;
9247         int surfacelistindex;
9248         int surfaceindex;
9249         int triangleindex;
9250         float localorigin[3];
9251         float localnormal[3];
9252         float localmins[3];
9253         float localmaxs[3];
9254         float localsize;
9255         //float normal[3];
9256         float planes[6][4];
9257         float angles[3];
9258         bih_t *bih;
9259         int bih_triangles_count;
9260         int bih_triangles[256];
9261         int bih_surfaces[256];
9262
9263         decalsystem = &ent->decalsystem;
9264         model = ent->model;
9265         if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9266         {
9267                 R_DecalSystem_Reset(&ent->decalsystem);
9268                 return;
9269         }
9270
9271         if (!model->brush.data_leafs && !cl_decals_models.integer)
9272         {
9273                 if (decalsystem->model)
9274                         R_DecalSystem_Reset(decalsystem);
9275                 return;
9276         }
9277
9278         if (decalsystem->model != model)
9279                 R_DecalSystem_Reset(decalsystem);
9280         decalsystem->model = model;
9281
9282         RSurf_ActiveModelEntity(ent, true, false, false);
9283
9284         Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9285         Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9286         VectorNormalize(localnormal);
9287         localsize = worldsize*rsurface.inversematrixscale;
9288         localmins[0] = localorigin[0] - localsize;
9289         localmins[1] = localorigin[1] - localsize;
9290         localmins[2] = localorigin[2] - localsize;
9291         localmaxs[0] = localorigin[0] + localsize;
9292         localmaxs[1] = localorigin[1] + localsize;
9293         localmaxs[2] = localorigin[2] + localsize;
9294
9295         //VectorCopy(localnormal, planes[4]);
9296         //VectorVectors(planes[4], planes[2], planes[0]);
9297         AnglesFromVectors(angles, localnormal, NULL, false);
9298         AngleVectors(angles, planes[0], planes[2], planes[4]);
9299         VectorNegate(planes[0], planes[1]);
9300         VectorNegate(planes[2], planes[3]);
9301         VectorNegate(planes[4], planes[5]);
9302         planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9303         planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9304         planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9305         planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9306         planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9307         planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9308
9309 #if 1
9310 // works
9311 {
9312         matrix4x4_t forwardprojection;
9313         Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9314         Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9315 }
9316 #else
9317 // broken
9318 {
9319         float projectionvector[4][3];
9320         VectorScale(planes[0], ilocalsize, projectionvector[0]);
9321         VectorScale(planes[2], ilocalsize, projectionvector[1]);
9322         VectorScale(planes[4], ilocalsize, projectionvector[2]);
9323         projectionvector[0][0] = planes[0][0] * ilocalsize;
9324         projectionvector[0][1] = planes[1][0] * ilocalsize;
9325         projectionvector[0][2] = planes[2][0] * ilocalsize;
9326         projectionvector[1][0] = planes[0][1] * ilocalsize;
9327         projectionvector[1][1] = planes[1][1] * ilocalsize;
9328         projectionvector[1][2] = planes[2][1] * ilocalsize;
9329         projectionvector[2][0] = planes[0][2] * ilocalsize;
9330         projectionvector[2][1] = planes[1][2] * ilocalsize;
9331         projectionvector[2][2] = planes[2][2] * ilocalsize;
9332         projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9333         projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9334         projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9335         Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9336 }
9337 #endif
9338
9339         dynamic = model->surfmesh.isanimated;
9340         numsurfacelist = model->nummodelsurfaces;
9341         surfacelist = model->sortedmodelsurfaces;
9342         surfaces = model->data_surfaces;
9343
9344         bih = NULL;
9345         bih_triangles_count = -1;
9346         if(!dynamic)
9347         {
9348                 if(model->render_bih.numleafs)
9349                         bih = &model->render_bih;
9350                 else if(model->collision_bih.numleafs)
9351                         bih = &model->collision_bih;
9352         }
9353         if(bih)
9354                 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9355         if(bih_triangles_count == 0)
9356                 return;
9357         if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9358                 return;
9359         if(bih_triangles_count > 0)
9360         {
9361                 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9362                 {
9363                         surfaceindex = bih_surfaces[triangleindex];
9364                         surface = surfaces + surfaceindex;
9365                         texture = surface->texture;
9366                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9367                                 continue;
9368                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9369                                 continue;
9370                         R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9371                 }
9372         }
9373         else
9374         {
9375                 for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
9376                 {
9377                         surfaceindex = surfacelist[surfacelistindex];
9378                         surface = surfaces + surfaceindex;
9379                         // check cull box first because it rejects more than any other check
9380                         if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9381                                 continue;
9382                         // skip transparent surfaces
9383                         texture = surface->texture;
9384                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9385                                 continue;
9386                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9387                                 continue;
9388                         numtriangles = surface->num_triangles;
9389                         for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9390                                 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9391                 }
9392         }
9393 }
9394
9395 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9396 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)
9397 {
9398         int renderentityindex;
9399         float worldmins[3];
9400         float worldmaxs[3];
9401         entity_render_t *ent;
9402
9403         worldmins[0] = worldorigin[0] - worldsize;
9404         worldmins[1] = worldorigin[1] - worldsize;
9405         worldmins[2] = worldorigin[2] - worldsize;
9406         worldmaxs[0] = worldorigin[0] + worldsize;
9407         worldmaxs[1] = worldorigin[1] + worldsize;
9408         worldmaxs[2] = worldorigin[2] + worldsize;
9409
9410         R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9411
9412         for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9413         {
9414                 ent = r_refdef.scene.entities[renderentityindex];
9415                 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9416                         continue;
9417
9418                 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9419         }
9420 }
9421
9422 typedef struct r_decalsystem_splatqueue_s
9423 {
9424         vec3_t worldorigin;
9425         vec3_t worldnormal;
9426         float color[4];
9427         float tcrange[4];
9428         float worldsize;
9429         unsigned int decalsequence;
9430 }
9431 r_decalsystem_splatqueue_t;
9432
9433 int r_decalsystem_numqueued = 0;
9434 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9435
9436 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)
9437 {
9438         r_decalsystem_splatqueue_t *queue;
9439
9440         if (r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9441                 return;
9442
9443         queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9444         VectorCopy(worldorigin, queue->worldorigin);
9445         VectorCopy(worldnormal, queue->worldnormal);
9446         Vector4Set(queue->color, r, g, b, a);
9447         Vector4Set(queue->tcrange, s1, t1, s2, t2);
9448         queue->worldsize = worldsize;
9449         queue->decalsequence = cl.decalsequence++;
9450 }
9451
9452 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9453 {
9454         int i;
9455         r_decalsystem_splatqueue_t *queue;
9456
9457         for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9458                 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);
9459         r_decalsystem_numqueued = 0;
9460 }
9461
9462 extern cvar_t cl_decals_max;
9463 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9464 {
9465         int i;
9466         decalsystem_t *decalsystem = &ent->decalsystem;
9467         int numdecals;
9468         unsigned int killsequence;
9469         tridecal_t *decal;
9470         float frametime;
9471         float lifetime;
9472
9473         if (!decalsystem->numdecals)
9474                 return;
9475
9476         if (r_showsurfaces.integer)
9477                 return;
9478
9479         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9480         {
9481                 R_DecalSystem_Reset(decalsystem);
9482                 return;
9483         }
9484
9485         killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9486         lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9487
9488         if (decalsystem->lastupdatetime)
9489                 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9490         else
9491                 frametime = 0;
9492         decalsystem->lastupdatetime = r_refdef.scene.time;
9493         numdecals = decalsystem->numdecals;
9494
9495         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9496         {
9497                 if (decal->color4f[0][3])
9498                 {
9499                         decal->lived += frametime;
9500                         if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9501                         {
9502                                 memset(decal, 0, sizeof(*decal));
9503                                 if (decalsystem->freedecal > i)
9504                                         decalsystem->freedecal = i;
9505                         }
9506                 }
9507         }
9508         decal = decalsystem->decals;
9509         while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9510                 numdecals--;
9511
9512         // collapse the array by shuffling the tail decals into the gaps
9513         for (;;)
9514         {
9515                 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
9516                         decalsystem->freedecal++;
9517                 if (decalsystem->freedecal == numdecals)
9518                         break;
9519                 decal[decalsystem->freedecal] = decal[--numdecals];
9520         }
9521
9522         decalsystem->numdecals = numdecals;
9523
9524         if (numdecals <= 0)
9525         {
9526                 // if there are no decals left, reset decalsystem
9527                 R_DecalSystem_Reset(decalsystem);
9528         }
9529 }
9530
9531 extern skinframe_t *decalskinframe;
9532 static void R_DrawModelDecals_Entity(entity_render_t *ent)
9533 {
9534         int i;
9535         decalsystem_t *decalsystem = &ent->decalsystem;
9536         int numdecals;
9537         tridecal_t *decal;
9538         float faderate;
9539         float alpha;
9540         float *v3f;
9541         float *c4f;
9542         float *t2f;
9543         const int *e;
9544         const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
9545         int numtris = 0;
9546
9547         numdecals = decalsystem->numdecals;
9548         if (!numdecals)
9549                 return;
9550
9551         if (r_showsurfaces.integer)
9552                 return;
9553
9554         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9555         {
9556                 R_DecalSystem_Reset(decalsystem);
9557                 return;
9558         }
9559
9560         // if the model is static it doesn't matter what value we give for
9561         // wantnormals and wanttangents, so this logic uses only rules applicable
9562         // to a model, knowing that they are meaningless otherwise
9563         RSurf_ActiveModelEntity(ent, false, false, false);
9564
9565         decalsystem->lastupdatetime = r_refdef.scene.time;
9566
9567         faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
9568
9569         // update vertex positions for animated models
9570         v3f = decalsystem->vertex3f;
9571         c4f = decalsystem->color4f;
9572         t2f = decalsystem->texcoord2f;
9573         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9574         {
9575                 if (!decal->color4f[0][3])
9576                         continue;
9577
9578                 if (surfacevisible && !surfacevisible[decal->surfaceindex])
9579                         continue;
9580
9581                 // skip backfaces
9582                 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
9583                         continue;
9584
9585                 // update color values for fading decals
9586                 if (decal->lived >= cl_decals_time.value)
9587                         alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
9588                 else
9589                         alpha = 1.0f;
9590
9591                 c4f[ 0] = decal->color4f[0][0] * alpha;
9592                 c4f[ 1] = decal->color4f[0][1] * alpha;
9593                 c4f[ 2] = decal->color4f[0][2] * alpha;
9594                 c4f[ 3] = 1;
9595                 c4f[ 4] = decal->color4f[1][0] * alpha;
9596                 c4f[ 5] = decal->color4f[1][1] * alpha;
9597                 c4f[ 6] = decal->color4f[1][2] * alpha;
9598                 c4f[ 7] = 1;
9599                 c4f[ 8] = decal->color4f[2][0] * alpha;
9600                 c4f[ 9] = decal->color4f[2][1] * alpha;
9601                 c4f[10] = decal->color4f[2][2] * alpha;
9602                 c4f[11] = 1;
9603
9604                 t2f[0] = decal->texcoord2f[0][0];
9605                 t2f[1] = decal->texcoord2f[0][1];
9606                 t2f[2] = decal->texcoord2f[1][0];
9607                 t2f[3] = decal->texcoord2f[1][1];
9608                 t2f[4] = decal->texcoord2f[2][0];
9609                 t2f[5] = decal->texcoord2f[2][1];
9610
9611                 // update vertex positions for animated models
9612                 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
9613                 {
9614                         e = rsurface.modelelement3i + 3*decal->triangleindex;
9615                         VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
9616                         VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
9617                         VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
9618                 }
9619                 else
9620                 {
9621                         VectorCopy(decal->vertex3f[0], v3f);
9622                         VectorCopy(decal->vertex3f[1], v3f + 3);
9623                         VectorCopy(decal->vertex3f[2], v3f + 6);
9624                 }
9625
9626                 if (r_refdef.fogenabled)
9627                 {
9628                         alpha = RSurf_FogVertex(v3f);
9629                         VectorScale(c4f, alpha, c4f);
9630                         alpha = RSurf_FogVertex(v3f + 3);
9631                         VectorScale(c4f + 4, alpha, c4f + 4);
9632                         alpha = RSurf_FogVertex(v3f + 6);
9633                         VectorScale(c4f + 8, alpha, c4f + 8);
9634                 }
9635
9636                 v3f += 9;
9637                 c4f += 12;
9638                 t2f += 6;
9639                 numtris++;
9640         }
9641
9642         if (numtris > 0)
9643         {
9644                 r_refdef.stats[r_stat_drawndecals] += numtris;
9645
9646                 // now render the decals all at once
9647                 // (this assumes they all use one particle font texture!)
9648                 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);
9649 //              R_Mesh_ResetTextureState();
9650                 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
9651                 GL_DepthMask(false);
9652                 GL_DepthRange(0, 1);
9653                 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
9654                 GL_DepthTest(true);
9655                 GL_CullFace(GL_NONE);
9656                 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
9657                 R_SetupShader_Generic(decalskinframe->base, false, false, false);
9658                 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
9659         }
9660 }
9661
9662 static void R_DrawModelDecals(void)
9663 {
9664         int i, numdecals;
9665
9666         // fade faster when there are too many decals
9667         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9668         for (i = 0;i < r_refdef.scene.numentities;i++)
9669                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9670
9671         R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
9672         for (i = 0;i < r_refdef.scene.numentities;i++)
9673                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9674                         R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
9675
9676         R_DecalSystem_ApplySplatEntitiesQueue();
9677
9678         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9679         for (i = 0;i < r_refdef.scene.numentities;i++)
9680                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9681
9682         r_refdef.stats[r_stat_totaldecals] += numdecals;
9683
9684         if (r_showsurfaces.integer || !r_drawdecals.integer)
9685                 return;
9686
9687         R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
9688
9689         for (i = 0;i < r_refdef.scene.numentities;i++)
9690         {
9691                 if (!r_refdef.viewcache.entityvisible[i])
9692                         continue;
9693                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9694                         R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
9695         }
9696 }
9697
9698 extern cvar_t mod_collision_bih;
9699 static void R_DrawDebugModel(void)
9700 {
9701         entity_render_t *ent = rsurface.entity;
9702         int i, j, flagsmask;
9703         const msurface_t *surface;
9704         dp_model_t *model = ent->model;
9705
9706         if (!sv.active  && !cls.demoplayback && ent != r_refdef.scene.worldentity)
9707                 return;
9708
9709         if (r_showoverdraw.value > 0)
9710         {
9711                 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
9712                 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9713                 R_SetupShader_Generic_NoTexture(false, false);
9714                 GL_DepthTest(false);
9715                 GL_DepthMask(false);
9716                 GL_DepthRange(0, 1);
9717                 GL_BlendFunc(GL_ONE, GL_ONE);
9718                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9719                 {
9720                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9721                                 continue;
9722                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9723                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9724                         {
9725                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
9726                                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
9727                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9728                                         GL_Color(c, 0, 0, 1.0f);
9729                                 else if (ent == r_refdef.scene.worldentity)
9730                                         GL_Color(c, c, c, 1.0f);
9731                                 else
9732                                         GL_Color(0, c, 0, 1.0f);
9733                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9734                                 RSurf_DrawBatch();
9735                         }
9736                 }
9737                 rsurface.texture = NULL;
9738         }
9739
9740         flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9741
9742 //      R_Mesh_ResetTextureState();
9743         R_SetupShader_Generic_NoTexture(false, false);
9744         GL_DepthRange(0, 1);
9745         GL_DepthTest(!r_showdisabledepthtest.integer);
9746         GL_DepthMask(false);
9747         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9748
9749         if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
9750         {
9751                 int triangleindex;
9752                 int bihleafindex;
9753                 qboolean cullbox = false;
9754                 const q3mbrush_t *brush;
9755                 const bih_t *bih = &model->collision_bih;
9756                 const bih_leaf_t *bihleaf;
9757                 float vertex3f[3][3];
9758                 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
9759                 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
9760                 {
9761                         if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
9762                                 continue;
9763                         switch (bihleaf->type)
9764                         {
9765                         case BIH_BRUSH:
9766                                 brush = model->brush.data_brushes + bihleaf->itemindex;
9767                                 if (brush->colbrushf && brush->colbrushf->numtriangles)
9768                                 {
9769                                         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);
9770                                         R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
9771                                         R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
9772                                 }
9773                                 break;
9774                         case BIH_COLLISIONTRIANGLE:
9775                                 triangleindex = bihleaf->itemindex;
9776                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
9777                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
9778                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
9779                                 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);
9780                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9781                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9782                                 break;
9783                         case BIH_RENDERTRIANGLE:
9784                                 triangleindex = bihleaf->itemindex;
9785                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
9786                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
9787                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
9788                                 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);
9789                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9790                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9791                                 break;
9792                         }
9793                 }
9794         }
9795
9796         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9797
9798 #ifndef USE_GLES2
9799         if (r_showtris.value > 0 && qglPolygonMode)
9800         {
9801                 if (r_showdisabledepthtest.integer)
9802                 {
9803                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9804                         GL_DepthMask(false);
9805                 }
9806                 else
9807                 {
9808                         GL_BlendFunc(GL_ONE, GL_ZERO);
9809                         GL_DepthMask(true);
9810                 }
9811                 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
9812                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9813                 {
9814                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9815                                 continue;
9816                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9817                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9818                         {
9819                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9820                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9821                                         GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
9822                                 else if (ent == r_refdef.scene.worldentity)
9823                                         GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
9824                                 else
9825                                         GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
9826                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9827                                 RSurf_DrawBatch();
9828                         }
9829                 }
9830                 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
9831                 rsurface.texture = NULL;
9832         }
9833
9834 # if 0
9835         // FIXME!  implement r_shownormals with just triangles
9836         if (r_shownormals.value != 0 && qglBegin)
9837         {
9838                 int l, k;
9839                 vec3_t v;
9840                 if (r_showdisabledepthtest.integer)
9841                 {
9842                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9843                         GL_DepthMask(false);
9844                 }
9845                 else
9846                 {
9847                         GL_BlendFunc(GL_ONE, GL_ZERO);
9848                         GL_DepthMask(true);
9849                 }
9850                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9851                 {
9852                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9853                                 continue;
9854                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9855                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9856                         {
9857                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9858                                 qglBegin(GL_LINES);
9859                                 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
9860                                 {
9861                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9862                                         {
9863                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9864                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9865                                                 qglVertex3f(v[0], v[1], v[2]);
9866                                                 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9867                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9868                                                 qglVertex3f(v[0], v[1], v[2]);
9869                                         }
9870                                 }
9871                                 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
9872                                 {
9873                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9874                                         {
9875                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9876                                                 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
9877                                                 qglVertex3f(v[0], v[1], v[2]);
9878                                                 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
9879                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9880                                                 qglVertex3f(v[0], v[1], v[2]);
9881                                         }
9882                                 }
9883                                 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
9884                                 {
9885                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9886                                         {
9887                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9888                                                 GL_Color(0, r_refdef.view.colorscale, 0, 1);
9889                                                 qglVertex3f(v[0], v[1], v[2]);
9890                                                 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
9891                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9892                                                 qglVertex3f(v[0], v[1], v[2]);
9893                                         }
9894                                 }
9895                                 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
9896                                 {
9897                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9898                                         {
9899                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9900                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9901                                                 qglVertex3f(v[0], v[1], v[2]);
9902                                                 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9903                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9904                                                 qglVertex3f(v[0], v[1], v[2]);
9905                                         }
9906                                 }
9907                                 qglEnd();
9908                                 CHECKGLERROR
9909                         }
9910                 }
9911                 rsurface.texture = NULL;
9912         }
9913 # endif
9914 #endif
9915 }
9916
9917 int r_maxsurfacelist = 0;
9918 const msurface_t **r_surfacelist = NULL;
9919 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass, qboolean ui)
9920 {
9921         int i, j, endj, flagsmask;
9922         dp_model_t *model = ent->model;
9923         msurface_t *surfaces;
9924         unsigned char *update;
9925         int numsurfacelist = 0;
9926         if (model == NULL)
9927                 return;
9928
9929         if (r_maxsurfacelist < model->num_surfaces)
9930         {
9931                 r_maxsurfacelist = model->num_surfaces;
9932                 if (r_surfacelist)
9933                         Mem_Free((msurface_t **)r_surfacelist);
9934                 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
9935         }
9936
9937         if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
9938                 RSurf_ActiveModelEntity(ent, false, false, false);
9939         else if (prepass)
9940                 RSurf_ActiveModelEntity(ent, true, true, true);
9941         else if (depthonly)
9942                 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
9943         else
9944                 RSurf_ActiveModelEntity(ent, true, true, false);
9945
9946         surfaces = model->data_surfaces;
9947         update = model->brushq1.lightmapupdateflags;
9948
9949         // update light styles
9950         if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0)
9951         {
9952                 model_brush_lightstyleinfo_t *style;
9953                 for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
9954                 {
9955                         if (style->value != r_refdef.scene.lightstylevalue[style->style])
9956                         {
9957                                 int *list = style->surfacelist;
9958                                 style->value = r_refdef.scene.lightstylevalue[style->style];
9959                                 for (j = 0;j < style->numsurfaces;j++)
9960                                         update[list[j]] = true;
9961                         }
9962                 }
9963         }
9964
9965         flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
9966
9967         if (debug)
9968         {
9969                 R_DrawDebugModel();
9970                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
9971                 return;
9972         }
9973
9974         rsurface.lightmaptexture = NULL;
9975         rsurface.deluxemaptexture = NULL;
9976         rsurface.uselightmaptexture = false;
9977         rsurface.texture = NULL;
9978         rsurface.rtlight = NULL;
9979         numsurfacelist = 0;
9980         // add visible surfaces to draw list
9981         if (ent == r_refdef.scene.worldentity)
9982         {
9983                 // for the world entity, check surfacevisible
9984                 for (i = 0;i < model->nummodelsurfaces;i++)
9985                 {
9986                         j = model->sortedmodelsurfaces[i];
9987                         if (r_refdef.viewcache.world_surfacevisible[j])
9988                                 r_surfacelist[numsurfacelist++] = surfaces + j;
9989                 }
9990         }
9991         else if (ui)
9992         {
9993                 // for ui we have to preserve the order of surfaces
9994                 for (i = 0; i < model->nummodelsurfaces; i++)
9995                         r_surfacelist[numsurfacelist++] = surfaces + model->firstmodelsurface + i;
9996         }
9997         else
9998         {
9999                 // add all surfaces
10000                 for (i = 0; i < model->nummodelsurfaces; i++)
10001                         r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
10002         }
10003         // don't do anything if there were no surfaces
10004         if (!numsurfacelist)
10005         {
10006                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10007                 return;
10008         }
10009         // update lightmaps if needed
10010         if (update)
10011         {
10012                 int updated = 0;
10013                 for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
10014                 {
10015                         if (update[j])
10016                         {
10017                                 updated++;
10018                                 R_BuildLightMap(ent, surfaces + j);
10019                         }
10020                 }
10021         }
10022
10023         R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass, ui);
10024
10025         // add to stats if desired
10026         if (r_speeds.integer && !skysurfaces && !depthonly)
10027         {
10028                 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10029                 for (j = 0;j < numsurfacelist;j++)
10030                         r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10031         }
10032
10033         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10034 }
10035
10036 void R_DebugLine(vec3_t start, vec3_t end)
10037 {
10038         dp_model_t *mod = CL_Mesh_UI();
10039         msurface_t *surf;
10040         int e0, e1, e2, e3;
10041         float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10042         float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10043         float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10044         vec4_t w[2], s[2];
10045
10046         // transform to screen coords first
10047         Vector4Set(w[0], start[0], start[1], start[2], 1);
10048         Vector4Set(w[1], end[0], end[1], end[2], 1);
10049         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10050         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10051         x1 = s[0][0] * vid_conwidth.value / vid.width;
10052         y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10053         x2 = s[1][0] * vid_conwidth.value / vid.width;
10054         y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10055         //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10056
10057         // add the line to the UI mesh for drawing later
10058
10059         // width is measured in real pixels
10060         if (fabs(x2 - x1) > fabs(y2 - y1))
10061         {
10062                 offsetx = 0;
10063                 offsety = 0.5f * width * vid_conheight.value / vid.height;
10064         }
10065         else
10066         {
10067                 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10068                 offsety = 0;
10069         }
10070         surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_WALL | MATERIALFLAG_VERTEXCOLOR | MATERIALFLAG_ALPHAGEN_VERTEX), true);
10071         e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10072         e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10073         e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10074         e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10075         Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10076         Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10077
10078 }
10079
10080
10081 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)
10082 {
10083         static texture_t texture;
10084
10085         // fake enough texture and surface state to render this geometry
10086
10087         texture.update_lastrenderframe = -1; // regenerate this texture
10088         texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10089         texture.basealpha = 1.0f;
10090         texture.currentskinframe = skinframe;
10091         texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10092         texture.offsetmapping = OFFSETMAPPING_OFF;
10093         texture.offsetscale = 1;
10094         texture.specularscalemod = 1;
10095         texture.specularpowermod = 1;
10096         texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10097
10098         R_DrawCustomSurface_Texture(&texture, texmatrix, materialflags, firstvertex, numvertices, firsttriangle, numtriangles, writedepth, prepass, ui);
10099 }
10100
10101 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)
10102 {
10103         static msurface_t surface;
10104         const msurface_t *surfacelist = &surface;
10105
10106         // fake enough texture and surface state to render this geometry
10107         surface.texture = texture;
10108         surface.num_triangles = numtriangles;
10109         surface.num_firsttriangle = firsttriangle;
10110         surface.num_vertices = numvertices;
10111         surface.num_firstvertex = firstvertex;
10112
10113         // now render it
10114         rsurface.texture = R_GetCurrentTexture(surface.texture);
10115         rsurface.lightmaptexture = NULL;
10116         rsurface.deluxemaptexture = NULL;
10117         rsurface.uselightmaptexture = false;
10118         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass, ui);
10119 }