]> git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
Fix a few compile warnings. Remove unused locals.
[xonotic/darkplaces.git] / gl_rmain.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_main.c
21
22 #include "quakedef.h"
23 #include "r_shadow.h"
24 #include "polygon.h"
25 #include "image.h"
26 #include "ft2.h"
27 #include "csprogs.h"
28 #include "cl_video.h"
29 #include "cl_collision.h"
30
31 #ifdef WIN32
32 // Enable NVIDIA High Performance Graphics while using Integrated Graphics.
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36 __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
37 #ifdef __cplusplus
38 }
39 #endif
40 #endif
41
42 mempool_t *r_main_mempool;
43 rtexturepool_t *r_main_texturepool;
44
45 int r_textureframe = 0; ///< used only by R_GetCurrentTexture, incremented per view and per UI render
46
47 static qboolean r_loadnormalmap;
48 static qboolean r_loadgloss;
49 qboolean r_loadfog;
50 static qboolean r_loaddds;
51 static qboolean r_savedds;
52 static qboolean r_gpuskeletal;
53
54 //
55 // screen size info
56 //
57 r_refdef_t r_refdef;
58
59 cvar_t r_motionblur = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur", "0", "screen motionblur - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
60 cvar_t r_damageblur = {CVAR_CLIENT | CVAR_SAVE, "r_damageblur", "0", "screen motionblur based on damage - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
61 cvar_t r_motionblur_averaging = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_averaging", "0.1", "sliding average reaction time for velocity (higher = slower adaption to change)"};
62 cvar_t r_motionblur_randomize = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"};
63 cvar_t r_motionblur_minblur = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_minblur", "0.5", "factor of blur to apply at all times (always have this amount of blur no matter what the other factors are)"};
64 cvar_t r_motionblur_maxblur = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_maxblur", "0.9", "maxmimum amount of blur"};
65 cvar_t r_motionblur_velocityfactor = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_velocityfactor", "1", "factoring in of player velocity to the blur equation - the faster the player moves around the map, the more blur they get"};
66 cvar_t r_motionblur_velocityfactor_minspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_velocityfactor_minspeed", "400", "lower value of velocity when it starts to factor into blur equation"};
67 cvar_t r_motionblur_velocityfactor_maxspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_velocityfactor_maxspeed", "800", "upper value of velocity when it reaches the peak factor into blur equation"};
68 cvar_t r_motionblur_mousefactor = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_mousefactor", "2", "factoring in of mouse acceleration to the blur equation - the faster the player turns their mouse, the more blur they get"};
69 cvar_t r_motionblur_mousefactor_minspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_mousefactor_minspeed", "0", "lower value of mouse acceleration when it starts to factor into blur equation"};
70 cvar_t r_motionblur_mousefactor_maxspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_mousefactor_maxspeed", "50", "upper value of mouse acceleration when it reaches the peak factor into blur equation"};
71
72 cvar_t r_depthfirst = {CVAR_CLIENT | CVAR_SAVE, "r_depthfirst", "0", "renders a depth-only version of the scene before normal rendering begins to eliminate overdraw, values: 0 = off, 1 = world depth, 2 = world and model depth"};
73 cvar_t r_useinfinitefarclip = {CVAR_CLIENT | CVAR_SAVE, "r_useinfinitefarclip", "1", "enables use of a special kind of projection matrix that has an extremely large farclip"};
74 cvar_t r_farclip_base = {CVAR_CLIENT, "r_farclip_base", "65536", "farclip (furthest visible distance) for rendering when r_useinfinitefarclip is 0"};
75 cvar_t r_farclip_world = {CVAR_CLIENT, "r_farclip_world", "2", "adds map size to farclip multiplied by this value"};
76 cvar_t r_nearclip = {CVAR_CLIENT, "r_nearclip", "1", "distance from camera of nearclip plane" };
77 cvar_t r_deformvertexes = {CVAR_CLIENT, "r_deformvertexes", "1", "allows use of deformvertexes in shader files (can be turned off to check performance impact)"};
78 cvar_t r_transparent = {CVAR_CLIENT, "r_transparent", "1", "allows use of transparent surfaces (can be turned off to check performance impact)"};
79 cvar_t r_transparent_alphatocoverage = {CVAR_CLIENT, "r_transparent_alphatocoverage", "1", "enables GL_ALPHA_TO_COVERAGE antialiasing technique on alphablend and alphatest surfaces when using vid_samples 2 or higher"};
80 cvar_t r_transparent_sortsurfacesbynearest = {CVAR_CLIENT, "r_transparent_sortsurfacesbynearest", "1", "sort entity and world surfaces by nearest point on bounding box instead of using the center of the bounding box, usually reduces sorting artifacts"};
81 cvar_t r_transparent_useplanardistance = {CVAR_CLIENT, "r_transparent_useplanardistance", "0", "sort transparent meshes by distance from view plane rather than spherical distance to the chosen point"};
82 cvar_t r_showoverdraw = {CVAR_CLIENT, "r_showoverdraw", "0", "shows overlapping geometry"};
83 cvar_t r_showbboxes = {CVAR_CLIENT, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
84 cvar_t r_showbboxes_client = {CVAR_CLIENT, "r_showbboxes_client", "0", "shows bounding boxes of clientside qc entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
85 cvar_t r_showsurfaces = {CVAR_CLIENT, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 2 shows triangle draw order (for analyzing whether meshes are optimized for vertex cache)"};
86 cvar_t r_showtris = {CVAR_CLIENT, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
87 cvar_t r_shownormals = {CVAR_CLIENT, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
88 cvar_t r_showlighting = {CVAR_CLIENT, "r_showlighting", "0", "shows areas lit by lights, useful for finding out why some areas of a map render slowly (bright orange = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
89 cvar_t r_showcollisionbrushes = {CVAR_CLIENT, "r_showcollisionbrushes", "0", "draws collision brushes in quake3 maps (mode 1), mode 2 disables rendering of world (trippy!)"};
90 cvar_t r_showcollisionbrushes_polygonfactor = {CVAR_CLIENT, "r_showcollisionbrushes_polygonfactor", "-1", "expands outward the brush polygons a little bit, used to make collision brushes appear infront of walls"};
91 cvar_t r_showcollisionbrushes_polygonoffset = {CVAR_CLIENT, "r_showcollisionbrushes_polygonoffset", "0", "nudges brush polygon depth in hardware depth units, used to make collision brushes appear infront of walls"};
92 cvar_t r_showdisabledepthtest = {CVAR_CLIENT, "r_showdisabledepthtest", "0", "disables depth testing on r_show* cvars, allowing you to see what hidden geometry the graphics card is processing"};
93 cvar_t r_showspriteedges = {CVAR_CLIENT, "r_showspriteedges", "0", "renders a debug outline to show the polygon shape of each sprite frame rendered (may be 2 or more in case of interpolated animations), for debugging rendering bugs with specific view types"};
94 cvar_t r_showparticleedges = {CVAR_CLIENT, "r_showparticleedges", "0", "renders a debug outline to show the polygon shape of each particle, for debugging rendering bugs with specific view types"};
95 cvar_t r_drawportals = {CVAR_CLIENT, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
96 cvar_t r_drawentities = {CVAR_CLIENT, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
97 cvar_t r_draw2d = {CVAR_CLIENT, "r_draw2d","1", "draw 2D stuff (dangerous to turn off)"};
98 cvar_t r_drawworld = {CVAR_CLIENT, "r_drawworld","1", "draw world (most static stuff)"};
99 cvar_t r_drawviewmodel = {CVAR_CLIENT, "r_drawviewmodel","1", "draw your weapon model"};
100 cvar_t r_drawexteriormodel = {CVAR_CLIENT, "r_drawexteriormodel","1", "draw your player model (e.g. in chase cam, reflections)"};
101 cvar_t r_cullentities_trace = {CVAR_CLIENT, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
102 cvar_t r_cullentities_trace_entityocclusion = {CVAR_CLIENT, "r_cullentities_trace_entityocclusion", "1", "check for occluding entities such as doors, not just world hull"};
103 cvar_t r_cullentities_trace_samples = {CVAR_CLIENT, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling (in addition to center sample)"};
104 cvar_t r_cullentities_trace_tempentitysamples = {CVAR_CLIENT, "r_cullentities_trace_tempentitysamples", "-1", "number of samples to test for entity culling of temp entities (including all CSQC entities), -1 disables trace culling on these entities to prevent flicker (pvs still applies)"};
105 cvar_t r_cullentities_trace_enlarge = {CVAR_CLIENT, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
106 cvar_t r_cullentities_trace_expand = {CVAR_CLIENT, "r_cullentities_trace_expand", "0", "box expanded by this many units for entity culling"};
107 cvar_t r_cullentities_trace_pad = {CVAR_CLIENT, "r_cullentities_trace_pad", "8", "accept traces that hit within this many units of the box"};
108 cvar_t r_cullentities_trace_delay = {CVAR_CLIENT, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
109 cvar_t r_cullentities_trace_eyejitter = {CVAR_CLIENT, "r_cullentities_trace_eyejitter", "16", "randomly offset rays from the eye by this much to reduce the odds of flickering"};
110 cvar_t r_sortentities = {CVAR_CLIENT, "r_sortentities", "0", "sort entities before drawing (might be faster)"};
111 cvar_t r_speeds = {CVAR_CLIENT, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
112 cvar_t r_fullbright = {CVAR_CLIENT, "r_fullbright","0", "makes map very bright and renders faster"};
113
114 cvar_t r_fullbright_directed = {CVAR_CLIENT, "r_fullbright_directed", "0", "render fullbright things (unlit worldmodel and EF_FULLBRIGHT entities, but not fullbright shaders) using a constant light direction instead to add more depth while keeping uniform brightness"};
115 cvar_t r_fullbright_directed_ambient = {CVAR_CLIENT, "r_fullbright_directed_ambient", "0.5", "ambient light multiplier for directed fullbright"};
116 cvar_t r_fullbright_directed_diffuse = {CVAR_CLIENT, "r_fullbright_directed_diffuse", "0.75", "diffuse light multiplier for directed fullbright"};
117 cvar_t r_fullbright_directed_pitch = {CVAR_CLIENT, "r_fullbright_directed_pitch", "20", "constant pitch direction ('height') of the fake light source to use for fullbright"};
118 cvar_t r_fullbright_directed_pitch_relative = {CVAR_CLIENT, "r_fullbright_directed_pitch_relative", "0", "whether r_fullbright_directed_pitch is interpreted as absolute (0) or relative (1) pitch"};
119
120 cvar_t r_wateralpha = {CVAR_CLIENT | CVAR_SAVE, "r_wateralpha","1", "opacity of water polygons"};
121 cvar_t r_dynamic = {CVAR_CLIENT | CVAR_SAVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
122 cvar_t r_fullbrights = {CVAR_CLIENT | CVAR_SAVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
123 cvar_t r_shadows = {CVAR_CLIENT | CVAR_SAVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this); when set to 2, always cast the shadows in the direction set by r_shadows_throwdirection, otherwise use the model lighting."};
124 cvar_t r_shadows_darken = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_darken", "0.5", "how much shadowed areas will be darkened"};
125 cvar_t r_shadows_throwdistance = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
126 cvar_t r_shadows_throwdirection = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_throwdirection", "0 0 -1", "override throwing direction for r_shadows 2"};
127 cvar_t r_shadows_drawafterrtlighting = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_drawafterrtlighting", "0", "draw fake shadows AFTER realtime lightning is drawn. May be useful for simulating fast sunlight on large outdoor maps with only one noshadow rtlight. The price is less realistic appearance of dynamic light shadows."};
128 cvar_t r_shadows_castfrombmodels = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
129 cvar_t r_shadows_focus = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_focus", "0 0 0", "offset the shadowed area focus"};
130 cvar_t r_shadows_shadowmapscale = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_shadowmapscale", "0.25", "higher values increase shadowmap quality at a cost of area covered (multiply global shadowmap precision) for fake shadows. Needs shadowmapping ON."};
131 cvar_t r_shadows_shadowmapbias = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_shadowmapbias", "-1", "sets shadowmap bias for fake shadows. -1 sets the value of r_shadow_shadowmapping_bias. Needs shadowmapping ON."};
132 cvar_t r_q1bsp_skymasking = {CVAR_CLIENT, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
133 cvar_t r_polygonoffset_submodel_factor = {CVAR_CLIENT, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
134 cvar_t r_polygonoffset_submodel_offset = {CVAR_CLIENT, "r_polygonoffset_submodel_offset", "14", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
135 cvar_t r_polygonoffset_decals_factor = {CVAR_CLIENT, "r_polygonoffset_decals_factor", "0", "biases depth values of decals to prevent z-fighting artifacts"};
136 cvar_t r_polygonoffset_decals_offset = {CVAR_CLIENT, "r_polygonoffset_decals_offset", "-14", "biases depth values of decals to prevent z-fighting artifacts"};
137 cvar_t r_fog_exp2 = {CVAR_CLIENT, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"};
138 cvar_t r_fog_clear = {CVAR_CLIENT, "r_fog_clear", "1", "clears renderbuffer with fog color before render starts"};
139 cvar_t r_drawfog = {CVAR_CLIENT | CVAR_SAVE, "r_drawfog", "1", "allows one to disable fog rendering"};
140 cvar_t r_transparentdepthmasking = {CVAR_CLIENT | CVAR_SAVE, "r_transparentdepthmasking", "0", "enables depth writes on transparent meshes whose materially is normally opaque, this prevents seeing the inside of a transparent mesh"};
141 cvar_t r_transparent_sortmindist = {CVAR_CLIENT | CVAR_SAVE, "r_transparent_sortmindist", "0", "lower distance limit for transparent sorting"};
142 cvar_t r_transparent_sortmaxdist = {CVAR_CLIENT | CVAR_SAVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"};
143 cvar_t r_transparent_sortarraysize = {CVAR_CLIENT | CVAR_SAVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"};
144 cvar_t r_celshading = {CVAR_CLIENT | CVAR_SAVE, "r_celshading", "0", "cartoon-style light shading (OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9
145 cvar_t r_celoutlines = {CVAR_CLIENT | CVAR_SAVE, "r_celoutlines", "0", "cartoon-style outlines (requires r_shadow_deferred; OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9
146
147 cvar_t gl_fogenable = {CVAR_CLIENT, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
148 cvar_t gl_fogdensity = {CVAR_CLIENT, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
149 cvar_t gl_fogred = {CVAR_CLIENT, "gl_fogred","0.3", "nehahra fog color red value (for Nehahra compatibility only)"};
150 cvar_t gl_foggreen = {CVAR_CLIENT, "gl_foggreen","0.3", "nehahra fog color green value (for Nehahra compatibility only)"};
151 cvar_t gl_fogblue = {CVAR_CLIENT, "gl_fogblue","0.3", "nehahra fog color blue value (for Nehahra compatibility only)"};
152 cvar_t gl_fogstart = {CVAR_CLIENT, "gl_fogstart", "0", "nehahra fog start distance (for Nehahra compatibility only)"};
153 cvar_t gl_fogend = {CVAR_CLIENT, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
154 cvar_t gl_skyclip = {CVAR_CLIENT, "gl_skyclip", "4608", "nehahra farclip distance - the real fog end (for Nehahra compatibility only)"};
155
156 cvar_t r_texture_dds_load = {CVAR_CLIENT | CVAR_SAVE, "r_texture_dds_load", "0", "load compressed dds/filename.dds texture instead of filename.tga, if the file exists (requires driver support)"};
157 cvar_t r_texture_dds_save = {CVAR_CLIENT | CVAR_SAVE, "r_texture_dds_save", "0", "save compressed dds/filename.dds texture when filename.tga is loaded, so that it can be loaded instead next time"};
158
159 cvar_t r_textureunits = {CVAR_CLIENT, "r_textureunits", "32", "number of texture units to use in GL 1.1 and GL 1.3 rendering paths"};
160 static cvar_t gl_combine = {CVAR_CLIENT | CVAR_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"};
161 static cvar_t r_glsl = {CVAR_CLIENT | CVAR_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"};
162
163 cvar_t r_usedepthtextures = {CVAR_CLIENT | CVAR_SAVE, "r_usedepthtextures", "1", "use depth texture instead of depth renderbuffer where possible, uses less video memory but may render slower (or faster) depending on hardware"};
164 cvar_t r_viewfbo = {CVAR_CLIENT | CVAR_SAVE, "r_viewfbo", "0", "enables use of an 8bit (1) or 16bit (2) or 32bit (3) per component float framebuffer render, which may be at a different resolution than the video mode"};
165 cvar_t r_rendertarget_debug = {CVAR_CLIENT, "r_rendertarget_debug", "-1", "replaces the view with the contents of the specified render target (by number - note that these can fluctuate depending on scene)"};
166 cvar_t r_viewscale = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale", "1", "scaling factor for resolution of the fbo rendering method, must be > 0, can be above 1 for a costly antialiasing behavior, typical values are 0.5 for 1/4th as many pixels rendered, or 1 for normal rendering"};
167 cvar_t r_viewscale_fpsscaling = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling", "0", "change resolution based on framerate"};
168 cvar_t r_viewscale_fpsscaling_min = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_min", "0.0625", "worst acceptable quality"};
169 cvar_t r_viewscale_fpsscaling_multiply = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_multiply", "5", "adjust quality up or down by the frametime difference from 1.0/target, multiplied by this factor"};
170 cvar_t r_viewscale_fpsscaling_stepsize = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_stepsize", "0.01", "smallest adjustment to hit the target framerate (this value prevents minute oscillations)"};
171 cvar_t r_viewscale_fpsscaling_stepmax = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_stepmax", "1.00", "largest adjustment to hit the target framerate (this value prevents wild overshooting of the estimate)"};
172 cvar_t r_viewscale_fpsscaling_target = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_target", "70", "desired framerate"};
173
174 cvar_t r_glsl_skeletal = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_skeletal", "1", "render skeletal models faster using a gpu-skinning technique"};
175 cvar_t r_glsl_deluxemapping = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
176 cvar_t r_glsl_offsetmapping = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
177 cvar_t r_glsl_offsetmapping_steps = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_steps", "2", "offset mapping steps (note: too high values may be not supported by your GPU)"};
178 cvar_t r_glsl_offsetmapping_reliefmapping = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
179 cvar_t r_glsl_offsetmapping_reliefmapping_steps = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_steps", "10", "relief mapping steps (note: too high values may be not supported by your GPU)"};
180 cvar_t r_glsl_offsetmapping_reliefmapping_refinesteps = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_refinesteps", "5", "relief mapping refine steps (these are a binary search executed as the last step as given by r_glsl_offsetmapping_reliefmapping_steps)"};
181 cvar_t r_glsl_offsetmapping_scale = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
182 cvar_t r_glsl_offsetmapping_lod = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_lod", "0", "apply distance-based level-of-detail correction to number of offsetmappig steps, effectively making it render faster on large open-area maps"};
183 cvar_t r_glsl_offsetmapping_lod_distance = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_lod_distance", "32", "first LOD level distance, second level (-50% steps) is 2x of this, third (33%) - 3x etc."};
184 cvar_t r_glsl_postprocess = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess", "0", "use a GLSL postprocessing shader"};
185 cvar_t r_glsl_postprocess_uservec1 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec1", "0 0 0 0", "a 4-component vector to pass as uservec1 to the postprocessing shader (only useful if default.glsl has been customized)"};
186 cvar_t r_glsl_postprocess_uservec2 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec2", "0 0 0 0", "a 4-component vector to pass as uservec2 to the postprocessing shader (only useful if default.glsl has been customized)"};
187 cvar_t r_glsl_postprocess_uservec3 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec3", "0 0 0 0", "a 4-component vector to pass as uservec3 to the postprocessing shader (only useful if default.glsl has been customized)"};
188 cvar_t r_glsl_postprocess_uservec4 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec4", "0 0 0 0", "a 4-component vector to pass as uservec4 to the postprocessing shader (only useful if default.glsl has been customized)"};
189 cvar_t r_glsl_postprocess_uservec1_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec1_enable", "1", "enables postprocessing uservec1 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
190 cvar_t r_glsl_postprocess_uservec2_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec2_enable", "1", "enables postprocessing uservec2 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
191 cvar_t r_glsl_postprocess_uservec3_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec3_enable", "1", "enables postprocessing uservec3 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
192 cvar_t r_glsl_postprocess_uservec4_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec4_enable", "1", "enables postprocessing uservec4 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
193
194 cvar_t r_water = {CVAR_CLIENT | CVAR_SAVE, "r_water", "0", "whether to use reflections and refraction on water surfaces (note: r_wateralpha must be set below 1)"};
195 cvar_t r_water_cameraentitiesonly = {CVAR_CLIENT | CVAR_SAVE, "r_water_cameraentitiesonly", "0", "whether to only show QC-defined reflections/refractions (typically used for camera- or portal-like effects)"};
196 cvar_t r_water_clippingplanebias = {CVAR_CLIENT | CVAR_SAVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
197 cvar_t r_water_resolutionmultiplier = {CVAR_CLIENT | CVAR_SAVE, "r_water_resolutionmultiplier", "0.5", "multiplier for screen resolution when rendering refracted/reflected scenes, 1 is full quality, lower values are faster"};
198 cvar_t r_water_refractdistort = {CVAR_CLIENT | CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
199 cvar_t r_water_reflectdistort = {CVAR_CLIENT | CVAR_SAVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
200 cvar_t r_water_scissormode = {CVAR_CLIENT, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
201 cvar_t r_water_lowquality = {CVAR_CLIENT, "r_water_lowquality", "0", "special option to accelerate water rendering: 1 disables all dynamic lights, 2 disables particles too"};
202 cvar_t r_water_hideplayer = {CVAR_CLIENT | CVAR_SAVE, "r_water_hideplayer", "0", "if set to 1 then player will be hidden in refraction views, if set to 2 then player will also be hidden in reflection views, player is always visible in camera views"};
203
204 cvar_t r_lerpsprites = {CVAR_CLIENT | CVAR_SAVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"};
205 cvar_t r_lerpmodels = {CVAR_CLIENT | CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
206 cvar_t r_lerplightstyles = {CVAR_CLIENT | CVAR_SAVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
207 cvar_t r_waterscroll = {CVAR_CLIENT | CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
208
209 cvar_t r_bloom = {CVAR_CLIENT | CVAR_SAVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
210 cvar_t r_bloom_colorscale = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorscale", "1", "how bright the glow is"};
211
212 cvar_t r_bloom_brighten = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_brighten", "2", "how bright the glow is, after subtract/power"};
213 cvar_t r_bloom_blur = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_blur", "4", "how large the glow is"};
214 cvar_t r_bloom_resolution = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
215 cvar_t r_bloom_colorexponent = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorexponent", "1", "how exaggerated the glow is"};
216 cvar_t r_bloom_colorsubtract = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorsubtract", "0.125", "reduces bloom colors by a certain amount"};
217 cvar_t r_bloom_scenebrightness = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_scenebrightness", "1", "global rendering brightness when bloom is enabled"};
218
219 cvar_t r_hdr_scenebrightness = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
220 cvar_t r_hdr_glowintensity = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
221 cvar_t r_hdr_irisadaptation = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation", "0", "adjust scene brightness according to light intensity at player location"};
222 cvar_t r_hdr_irisadaptation_multiplier = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_multiplier", "2", "brightness at which value will be 1.0"};
223 cvar_t r_hdr_irisadaptation_minvalue = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_minvalue", "0.5", "minimum value that can result from multiplier / brightness"};
224 cvar_t r_hdr_irisadaptation_maxvalue = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_maxvalue", "4", "maximum value that can result from multiplier / brightness"};
225 cvar_t r_hdr_irisadaptation_value = {CVAR_CLIENT, "r_hdr_irisadaptation_value", "1", "current value as scenebrightness multiplier, changes continuously when irisadaptation is active"};
226 cvar_t r_hdr_irisadaptation_fade_up = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_fade_up", "0.1", "fade rate at which value adjusts to darkness"};
227 cvar_t r_hdr_irisadaptation_fade_down = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_fade_down", "0.5", "fade rate at which value adjusts to brightness"};
228 cvar_t r_hdr_irisadaptation_radius = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_radius", "15", "lighting within this many units of the eye is averaged"};
229
230 cvar_t r_smoothnormals_areaweighting = {CVAR_CLIENT, "r_smoothnormals_areaweighting", "1", "uses significantly faster (and supposedly higher quality) area-weighted vertex normals and tangent vectors rather than summing normalized triangle normals and tangents"};
231
232 cvar_t developer_texturelogging = {CVAR_CLIENT, "developer_texturelogging", "0", "produces a textures.log file containing names of skins and map textures the engine tried to load"};
233
234 cvar_t gl_lightmaps = {CVAR_CLIENT, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers), a value of 2 keeps normalmap shading"};
235
236 cvar_t r_test = {CVAR_CLIENT, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
237
238 cvar_t r_batch_multidraw = {CVAR_CLIENT | CVAR_SAVE, "r_batch_multidraw", "1", "issue multiple glDrawElements calls when rendering a batch of surfaces with the same texture (otherwise the index data is copied to make it one draw)"};
239 cvar_t r_batch_multidraw_mintriangles = {CVAR_CLIENT | CVAR_SAVE, "r_batch_multidraw_mintriangles", "0", "minimum number of triangles to activate multidraw path (copying small groups of triangles may be faster)"};
240 cvar_t r_batch_debugdynamicvertexpath = {CVAR_CLIENT | CVAR_SAVE, "r_batch_debugdynamicvertexpath", "0", "force the dynamic batching code path for debugging purposes"};
241 cvar_t r_batch_dynamicbuffer = {CVAR_CLIENT | CVAR_SAVE, "r_batch_dynamicbuffer", "0", "use vertex/index buffers for drawing dynamic and copytriangles batches"};
242
243 cvar_t r_glsl_saturation = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
244 cvar_t r_glsl_saturation_redcompensate = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_saturation_redcompensate", "0", "a 'vampire sight' addition to desaturation effect, does compensation for red color, r_glsl_restart is required"};
245
246 cvar_t r_glsl_vertextextureblend_usebothalphas = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_vertextextureblend_usebothalphas", "0", "use both alpha layers on vertex blended surfaces, each alpha layer sets amount of 'blend leak' on another layer, requires mod_q3shader_force_terrain_alphaflag on."};
247
248 cvar_t r_framedatasize = {CVAR_CLIENT | CVAR_SAVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"};
249 cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
250 {
251         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"},
252         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"},
253         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"},
254         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
255 };
256
257 extern cvar_t v_glslgamma_2d;
258
259 extern qboolean v_flipped_state;
260
261 r_framebufferstate_t r_fb;
262
263 /// shadow volume bsp struct with automatically growing nodes buffer
264 svbsp_t r_svbsp;
265
266 int r_uniformbufferalignment = 32; // dynamically updated to match GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
267
268 rtexture_t *r_texture_blanknormalmap;
269 rtexture_t *r_texture_white;
270 rtexture_t *r_texture_grey128;
271 rtexture_t *r_texture_black;
272 rtexture_t *r_texture_notexture;
273 rtexture_t *r_texture_whitecube;
274 rtexture_t *r_texture_normalizationcube;
275 rtexture_t *r_texture_fogattenuation;
276 rtexture_t *r_texture_fogheighttexture;
277 rtexture_t *r_texture_gammaramps;
278 unsigned int r_texture_gammaramps_serial;
279 //rtexture_t *r_texture_fogintensity;
280 rtexture_t *r_texture_reflectcube;
281
282 // TODO: hash lookups?
283 typedef struct cubemapinfo_s
284 {
285         char basename[64];
286         rtexture_t *texture;
287 }
288 cubemapinfo_t;
289
290 int r_texture_numcubemaps;
291 cubemapinfo_t *r_texture_cubemaps[MAX_CUBEMAPS];
292
293 unsigned int r_queries[MAX_OCCLUSION_QUERIES];
294 unsigned int r_numqueries;
295 unsigned int r_maxqueries;
296
297 typedef struct r_qwskincache_s
298 {
299         char name[MAX_QPATH];
300         skinframe_t *skinframe;
301 }
302 r_qwskincache_t;
303
304 static r_qwskincache_t *r_qwskincache;
305 static int r_qwskincache_size;
306
307 /// vertex coordinates for a quad that covers the screen exactly
308 extern const float r_screenvertex3f[12];
309 const float r_screenvertex3f[12] =
310 {
311         0, 0, 0,
312         1, 0, 0,
313         1, 1, 0,
314         0, 1, 0
315 };
316
317 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
318 {
319         int i;
320         for (i = 0;i < verts;i++)
321         {
322                 out[0] = in[0] * r;
323                 out[1] = in[1] * g;
324                 out[2] = in[2] * b;
325                 out[3] = in[3];
326                 in += 4;
327                 out += 4;
328         }
329 }
330
331 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
332 {
333         int i;
334         for (i = 0;i < verts;i++)
335         {
336                 out[0] = r;
337                 out[1] = g;
338                 out[2] = b;
339                 out[3] = a;
340                 out += 4;
341         }
342 }
343
344 // FIXME: move this to client?
345 void FOG_clear(void)
346 {
347         if (gamemode == GAME_NEHAHRA)
348         {
349                 Cvar_Set(&cvars_all, "gl_fogenable", "0");
350                 Cvar_Set(&cvars_all, "gl_fogdensity", "0.2");
351                 Cvar_Set(&cvars_all, "gl_fogred", "0.3");
352                 Cvar_Set(&cvars_all, "gl_foggreen", "0.3");
353                 Cvar_Set(&cvars_all, "gl_fogblue", "0.3");
354         }
355         r_refdef.fog_density = 0;
356         r_refdef.fog_red = 0;
357         r_refdef.fog_green = 0;
358         r_refdef.fog_blue = 0;
359         r_refdef.fog_alpha = 1;
360         r_refdef.fog_start = 0;
361         r_refdef.fog_end = 16384;
362         r_refdef.fog_height = 1<<30;
363         r_refdef.fog_fadedepth = 128;
364         memset(r_refdef.fog_height_texturename, 0, sizeof(r_refdef.fog_height_texturename));
365 }
366
367 static void R_BuildBlankTextures(void)
368 {
369         unsigned char data[4];
370         data[2] = 128; // normal X
371         data[1] = 128; // normal Y
372         data[0] = 255; // normal Z
373         data[3] = 255; // height
374         r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
375         data[0] = 255;
376         data[1] = 255;
377         data[2] = 255;
378         data[3] = 255;
379         r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
380         data[0] = 128;
381         data[1] = 128;
382         data[2] = 128;
383         data[3] = 255;
384         r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
385         data[0] = 0;
386         data[1] = 0;
387         data[2] = 0;
388         data[3] = 255;
389         r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
390 }
391
392 static void R_BuildNoTexture(void)
393 {
394         int x, y;
395         unsigned char pix[16][16][4];
396         // this makes a light grey/dark grey checkerboard texture
397         for (y = 0;y < 16;y++)
398         {
399                 for (x = 0;x < 16;x++)
400                 {
401                         if ((y < 8) ^ (x < 8))
402                         {
403                                 pix[y][x][0] = 128;
404                                 pix[y][x][1] = 128;
405                                 pix[y][x][2] = 128;
406                                 pix[y][x][3] = 255;
407                         }
408                         else
409                         {
410                                 pix[y][x][0] = 64;
411                                 pix[y][x][1] = 64;
412                                 pix[y][x][2] = 64;
413                                 pix[y][x][3] = 255;
414                         }
415                 }
416         }
417         r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, -1, NULL);
418 }
419
420 static void R_BuildWhiteCube(void)
421 {
422         unsigned char data[6*1*1*4];
423         memset(data, 255, sizeof(data));
424         r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
425 }
426
427 static void R_BuildNormalizationCube(void)
428 {
429         int x, y, side;
430         vec3_t v;
431         vec_t s, t, intensity;
432 #define NORMSIZE 64
433         unsigned char *data;
434         data = (unsigned char *)Mem_Alloc(tempmempool, 6*NORMSIZE*NORMSIZE*4);
435         for (side = 0;side < 6;side++)
436         {
437                 for (y = 0;y < NORMSIZE;y++)
438                 {
439                         for (x = 0;x < NORMSIZE;x++)
440                         {
441                                 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
442                                 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
443                                 switch(side)
444                                 {
445                                 default:
446                                 case 0:
447                                         v[0] = 1;
448                                         v[1] = -t;
449                                         v[2] = -s;
450                                         break;
451                                 case 1:
452                                         v[0] = -1;
453                                         v[1] = -t;
454                                         v[2] = s;
455                                         break;
456                                 case 2:
457                                         v[0] = s;
458                                         v[1] = 1;
459                                         v[2] = t;
460                                         break;
461                                 case 3:
462                                         v[0] = s;
463                                         v[1] = -1;
464                                         v[2] = -t;
465                                         break;
466                                 case 4:
467                                         v[0] = s;
468                                         v[1] = -t;
469                                         v[2] = 1;
470                                         break;
471                                 case 5:
472                                         v[0] = -s;
473                                         v[1] = -t;
474                                         v[2] = -1;
475                                         break;
476                                 }
477                                 intensity = 127.0f / sqrt(DotProduct(v, v));
478                                 data[((side*64+y)*64+x)*4+2] = (unsigned char)(128.0f + intensity * v[0]);
479                                 data[((side*64+y)*64+x)*4+1] = (unsigned char)(128.0f + intensity * v[1]);
480                                 data[((side*64+y)*64+x)*4+0] = (unsigned char)(128.0f + intensity * v[2]);
481                                 data[((side*64+y)*64+x)*4+3] = 255;
482                         }
483                 }
484         }
485         r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
486         Mem_Free(data);
487 }
488
489 static void R_BuildFogTexture(void)
490 {
491         int x, b;
492 #define FOGWIDTH 256
493         unsigned char data1[FOGWIDTH][4];
494         //unsigned char data2[FOGWIDTH][4];
495         double d, r, alpha;
496
497         r_refdef.fogmasktable_start = r_refdef.fog_start;
498         r_refdef.fogmasktable_alpha = r_refdef.fog_alpha;
499         r_refdef.fogmasktable_range = r_refdef.fogrange;
500         r_refdef.fogmasktable_density = r_refdef.fog_density;
501
502         r = r_refdef.fogmasktable_range / FOGMASKTABLEWIDTH;
503         for (x = 0;x < FOGMASKTABLEWIDTH;x++)
504         {
505                 d = (x * r - r_refdef.fogmasktable_start);
506                 if(developer_extra.integer)
507                         Con_DPrintf("%f ", d);
508                 d = max(0, d);
509                 if (r_fog_exp2.integer)
510                         alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d);
511                 else
512                         alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d);
513                 if(developer_extra.integer)
514                         Con_DPrintf(" : %f ", alpha);
515                 alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha;
516                 if(developer_extra.integer)
517                         Con_DPrintf(" = %f\n", alpha);
518                 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
519         }
520
521         for (x = 0;x < FOGWIDTH;x++)
522         {
523                 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
524                 data1[x][0] = b;
525                 data1[x][1] = b;
526                 data1[x][2] = b;
527                 data1[x][3] = 255;
528                 //data2[x][0] = 255 - b;
529                 //data2[x][1] = 255 - b;
530                 //data2[x][2] = 255 - b;
531                 //data2[x][3] = 255;
532         }
533         if (r_texture_fogattenuation)
534         {
535                 R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
536                 //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
537         }
538         else
539         {
540                 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
541                 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
542         }
543 }
544
545 static void R_BuildFogHeightTexture(void)
546 {
547         unsigned char *inpixels;
548         int size;
549         int x;
550         int y;
551         int j;
552         float c[4];
553         float f;
554         inpixels = NULL;
555         strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename));
556         if (r_refdef.fogheighttexturename[0])
557                 inpixels = loadimagepixelsbgra(r_refdef.fogheighttexturename, true, false, false, NULL);
558         if (!inpixels)
559         {
560                 r_refdef.fog_height_tablesize = 0;
561                 if (r_texture_fogheighttexture)
562                         R_FreeTexture(r_texture_fogheighttexture);
563                 r_texture_fogheighttexture = NULL;
564                 if (r_refdef.fog_height_table2d)
565                         Mem_Free(r_refdef.fog_height_table2d);
566                 r_refdef.fog_height_table2d = NULL;
567                 if (r_refdef.fog_height_table1d)
568                         Mem_Free(r_refdef.fog_height_table1d);
569                 r_refdef.fog_height_table1d = NULL;
570                 return;
571         }
572         size = image_width;
573         r_refdef.fog_height_tablesize = size;
574         r_refdef.fog_height_table1d = (unsigned char *)Mem_Alloc(r_main_mempool, size * 4);
575         r_refdef.fog_height_table2d = (unsigned char *)Mem_Alloc(r_main_mempool, size * size * 4);
576         memcpy(r_refdef.fog_height_table1d, inpixels, size * 4);
577         Mem_Free(inpixels);
578         // LadyHavoc: now the magic - what is that table2d for?  it is a cooked
579         // average fog color table accounting for every fog layer between a point
580         // and the camera.  (Note: attenuation is handled separately!)
581         for (y = 0;y < size;y++)
582         {
583                 for (x = 0;x < size;x++)
584                 {
585                         Vector4Clear(c);
586                         f = 0;
587                         if (x < y)
588                         {
589                                 for (j = x;j <= y;j++)
590                                 {
591                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
592                                         f++;
593                                 }
594                         }
595                         else
596                         {
597                                 for (j = x;j >= y;j--)
598                                 {
599                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
600                                         f++;
601                                 }
602                         }
603                         f = 1.0f / f;
604                         r_refdef.fog_height_table2d[(y*size+x)*4+0] = (unsigned char)(c[0] * f);
605                         r_refdef.fog_height_table2d[(y*size+x)*4+1] = (unsigned char)(c[1] * f);
606                         r_refdef.fog_height_table2d[(y*size+x)*4+2] = (unsigned char)(c[2] * f);
607                         r_refdef.fog_height_table2d[(y*size+x)*4+3] = (unsigned char)(c[3] * f);
608                 }
609         }
610         r_texture_fogheighttexture = R_LoadTexture2D(r_main_texturepool, "fogheighttable", size, size, r_refdef.fog_height_table2d, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_CLAMP, -1, NULL);
611 }
612
613 //=======================================================================================================================================================
614
615 static const char *builtinshaderstrings[] =
616 {
617 #include "shader_glsl.h"
618 0
619 };
620
621 //=======================================================================================================================================================
622
623 typedef struct shaderpermutationinfo_s
624 {
625         const char *pretext;
626         const char *name;
627 }
628 shaderpermutationinfo_t;
629
630 typedef struct shadermodeinfo_s
631 {
632         const char *sourcebasename;
633         const char *extension;
634         const char **builtinshaderstrings;
635         const char *pretext;
636         const char *name;
637         char *filename;
638         char *builtinstring;
639         int builtincrc;
640 }
641 shadermodeinfo_t;
642
643 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
644 shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
645 {
646         {"#define USEDIFFUSE\n", " diffuse"},
647         {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
648         {"#define USEVIEWTINT\n", " viewtint"},
649         {"#define USECOLORMAPPING\n", " colormapping"},
650         {"#define USESATURATION\n", " saturation"},
651         {"#define USEFOGINSIDE\n", " foginside"},
652         {"#define USEFOGOUTSIDE\n", " fogoutside"},
653         {"#define USEFOGHEIGHTTEXTURE\n", " fogheighttexture"},
654         {"#define USEFOGALPHAHACK\n", " fogalphahack"},
655         {"#define USEGAMMARAMPS\n", " gammaramps"},
656         {"#define USECUBEFILTER\n", " cubefilter"},
657         {"#define USEGLOW\n", " glow"},
658         {"#define USEBLOOM\n", " bloom"},
659         {"#define USESPECULAR\n", " specular"},
660         {"#define USEPOSTPROCESSING\n", " postprocessing"},
661         {"#define USEREFLECTION\n", " reflection"},
662         {"#define USEOFFSETMAPPING\n", " offsetmapping"},
663         {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
664         {"#define USESHADOWMAP2D\n", " shadowmap2d"},
665         {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm
666         {"#define USESHADOWMAPORTHO\n", " shadowmaportho"},
667         {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
668         {"#define USEALPHAKILL\n", " alphakill"},
669         {"#define USEREFLECTCUBE\n", " reflectcube"},
670         {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"},
671         {"#define USEBOUNCEGRID\n", " bouncegrid"},
672         {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm
673         {"#define USETRIPPY\n", " trippy"},
674         {"#define USEDEPTHRGB\n", " depthrgb"},
675         {"#define USEALPHAGENVERTEX\n", " alphagenvertex"},
676         {"#define USESKELETAL\n", " skeletal"},
677         {"#define USEOCCLUDE\n", " occlude"}
678 };
679
680 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
681 shadermodeinfo_t shadermodeinfo[SHADERLANGUAGE_COUNT][SHADERMODE_COUNT] =
682 {
683         // SHADERLANGUAGE_GLSL
684         {
685                 {"combined", "glsl", builtinshaderstrings, "#define MODE_GENERIC\n", " generic"},
686                 {"combined", "glsl", builtinshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
687                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
688                 {"combined", "glsl", builtinshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
689                 {"combined", "glsl", builtinshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
690                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
691                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
692                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
693                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
694                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
695                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
696                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
697                 {"combined", "glsl", builtinshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
698                 {"combined", "glsl", builtinshaderstrings, "#define MODE_WATER\n", " water"},
699                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
700                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
701         },
702 };
703
704 struct r_glsl_permutation_s;
705 typedef struct r_glsl_permutation_s
706 {
707         /// hash lookup data
708         struct r_glsl_permutation_s *hashnext;
709         unsigned int mode;
710         dpuint64 permutation;
711
712         /// indicates if we have tried compiling this permutation already
713         qboolean compiled;
714         /// 0 if compilation failed
715         int program;
716         // texture units assigned to each detected uniform
717         int tex_Texture_First;
718         int tex_Texture_Second;
719         int tex_Texture_GammaRamps;
720         int tex_Texture_Normal;
721         int tex_Texture_Color;
722         int tex_Texture_Gloss;
723         int tex_Texture_Glow;
724         int tex_Texture_SecondaryNormal;
725         int tex_Texture_SecondaryColor;
726         int tex_Texture_SecondaryGloss;
727         int tex_Texture_SecondaryGlow;
728         int tex_Texture_Pants;
729         int tex_Texture_Shirt;
730         int tex_Texture_FogHeightTexture;
731         int tex_Texture_FogMask;
732         int tex_Texture_Lightmap;
733         int tex_Texture_Deluxemap;
734         int tex_Texture_Attenuation;
735         int tex_Texture_Cube;
736         int tex_Texture_Refraction;
737         int tex_Texture_Reflection;
738         int tex_Texture_ShadowMap2D;
739         int tex_Texture_CubeProjection;
740         int tex_Texture_ScreenNormalMap;
741         int tex_Texture_ScreenDiffuse;
742         int tex_Texture_ScreenSpecular;
743         int tex_Texture_ReflectMask;
744         int tex_Texture_ReflectCube;
745         int tex_Texture_BounceGrid;
746         /// locations of detected uniforms in program object, or -1 if not found
747         int loc_Texture_First;
748         int loc_Texture_Second;
749         int loc_Texture_GammaRamps;
750         int loc_Texture_Normal;
751         int loc_Texture_Color;
752         int loc_Texture_Gloss;
753         int loc_Texture_Glow;
754         int loc_Texture_SecondaryNormal;
755         int loc_Texture_SecondaryColor;
756         int loc_Texture_SecondaryGloss;
757         int loc_Texture_SecondaryGlow;
758         int loc_Texture_Pants;
759         int loc_Texture_Shirt;
760         int loc_Texture_FogHeightTexture;
761         int loc_Texture_FogMask;
762         int loc_Texture_Lightmap;
763         int loc_Texture_Deluxemap;
764         int loc_Texture_Attenuation;
765         int loc_Texture_Cube;
766         int loc_Texture_Refraction;
767         int loc_Texture_Reflection;
768         int loc_Texture_ShadowMap2D;
769         int loc_Texture_CubeProjection;
770         int loc_Texture_ScreenNormalMap;
771         int loc_Texture_ScreenDiffuse;
772         int loc_Texture_ScreenSpecular;
773         int loc_Texture_ReflectMask;
774         int loc_Texture_ReflectCube;
775         int loc_Texture_BounceGrid;
776         int loc_Alpha;
777         int loc_BloomBlur_Parameters;
778         int loc_ClientTime;
779         int loc_Color_Ambient;
780         int loc_Color_Diffuse;
781         int loc_Color_Specular;
782         int loc_Color_Glow;
783         int loc_Color_Pants;
784         int loc_Color_Shirt;
785         int loc_DeferredColor_Ambient;
786         int loc_DeferredColor_Diffuse;
787         int loc_DeferredColor_Specular;
788         int loc_DeferredMod_Diffuse;
789         int loc_DeferredMod_Specular;
790         int loc_DistortScaleRefractReflect;
791         int loc_EyePosition;
792         int loc_FogColor;
793         int loc_FogHeightFade;
794         int loc_FogPlane;
795         int loc_FogPlaneViewDist;
796         int loc_FogRangeRecip;
797         int loc_LightColor;
798         int loc_LightDir;
799         int loc_LightPosition;
800         int loc_OffsetMapping_ScaleSteps;
801         int loc_OffsetMapping_LodDistance;
802         int loc_OffsetMapping_Bias;
803         int loc_PixelSize;
804         int loc_ReflectColor;
805         int loc_ReflectFactor;
806         int loc_ReflectOffset;
807         int loc_RefractColor;
808         int loc_Saturation;
809         int loc_ScreenCenterRefractReflect;
810         int loc_ScreenScaleRefractReflect;
811         int loc_ScreenToDepth;
812         int loc_ShadowMap_Parameters;
813         int loc_ShadowMap_TextureScale;
814         int loc_SpecularPower;
815         int loc_Skeletal_Transform12;
816         int loc_UserVec1;
817         int loc_UserVec2;
818         int loc_UserVec3;
819         int loc_UserVec4;
820         int loc_ViewTintColor;
821         int loc_ViewToLight;
822         int loc_ModelToLight;
823         int loc_TexMatrix;
824         int loc_BackgroundTexMatrix;
825         int loc_ModelViewProjectionMatrix;
826         int loc_ModelViewMatrix;
827         int loc_PixelToScreenTexCoord;
828         int loc_ModelToReflectCube;
829         int loc_ShadowMapMatrix;
830         int loc_BloomColorSubtract;
831         int loc_NormalmapScrollBlend;
832         int loc_BounceGridMatrix;
833         int loc_BounceGridIntensity;
834         /// uniform block bindings
835         int ubibind_Skeletal_Transform12_UniformBlock;
836         /// uniform block indices
837         int ubiloc_Skeletal_Transform12_UniformBlock;
838 }
839 r_glsl_permutation_t;
840
841 #define SHADERPERMUTATION_HASHSIZE 256
842
843
844 // non-degradable "lightweight" shader parameters to keep the permutations simpler
845 // these can NOT degrade! only use for simple stuff
846 enum
847 {
848         SHADERSTATICPARM_SATURATION_REDCOMPENSATE = 0, ///< red compensation filter for saturation
849         SHADERSTATICPARM_EXACTSPECULARMATH = 1, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
850         SHADERSTATICPARM_POSTPROCESS_USERVEC1 = 2, ///< postprocess uservec1 is enabled
851         SHADERSTATICPARM_POSTPROCESS_USERVEC2 = 3, ///< postprocess uservec2 is enabled
852         SHADERSTATICPARM_POSTPROCESS_USERVEC3 = 4, ///< postprocess uservec3 is enabled
853         SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5,  ///< postprocess uservec4 is enabled
854         SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending
855         SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7,  ///< LOD for offsetmapping
856         SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1
857         SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2
858         SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
859         SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
860         SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
861         SHADERSTATICPARM_FXAA = 13 ///< fast approximate anti aliasing
862 };
863 #define SHADERSTATICPARMS_COUNT 14
864
865 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
866 static int shaderstaticparms_count = 0;
867
868 static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0};
869 #define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F))
870
871 extern qboolean r_shadow_shadowmapsampler;
872 extern int r_shadow_shadowmappcf;
873 qboolean R_CompileShader_CheckStaticParms(void)
874 {
875         static int r_compileshader_staticparms_save[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5];
876         memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
877         memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
878
879         // detect all
880         if (r_glsl_saturation_redcompensate.integer)
881                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SATURATION_REDCOMPENSATE);
882         if (r_glsl_vertextextureblend_usebothalphas.integer)
883                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS);
884         if (r_shadow_glossexact.integer)
885                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_EXACTSPECULARMATH);
886         if (r_glsl_postprocess.integer)
887         {
888                 if (r_glsl_postprocess_uservec1_enable.integer)
889                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC1);
890                 if (r_glsl_postprocess_uservec2_enable.integer)
891                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC2);
892                 if (r_glsl_postprocess_uservec3_enable.integer)
893                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC3);
894                 if (r_glsl_postprocess_uservec4_enable.integer)
895                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
896         }
897         if (r_fxaa.integer)
898                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_FXAA);
899         if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
900                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
901
902         if (r_shadow_shadowmapsampler)
903                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER);
904         if (r_shadow_shadowmappcf > 1)
905                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2);
906         else if (r_shadow_shadowmappcf)
907                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1);
908         if (r_celshading.integer)
909                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING);
910         if (r_celoutlines.integer)
911                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES);
912
913         return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
914 }
915
916 #define R_COMPILESHADER_STATICPARM_EMIT(p, n) \
917         if(r_compileshader_staticparms[(p) >> 5] & (1 << ((p) & 0x1F))) \
918                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \
919         else \
920                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n"
921 static void R_CompileShader_AddStaticParms(unsigned int mode, dpuint64 permutation)
922 {
923         shaderstaticparms_count = 0;
924
925         // emit all
926         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SATURATION_REDCOMPENSATE, "SATURATION_REDCOMPENSATE");
927         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_EXACTSPECULARMATH, "USEEXACTSPECULARMATH");
928         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC1, "USERVEC1");
929         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC2, "USERVEC2");
930         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC3, "USERVEC3");
931         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4");
932         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS");
933         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD");
934         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1");
935         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2");
936         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
937         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
938         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
939         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
940 }
941
942 /// information about each possible shader permutation
943 r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
944 /// currently selected permutation
945 r_glsl_permutation_t *r_glsl_permutation;
946 /// storage for permutations linked in the hash table
947 memexpandablearray_t r_glsl_permutationarray;
948
949 static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, dpuint64 permutation)
950 {
951         //unsigned int hashdepth = 0;
952         unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
953         r_glsl_permutation_t *p;
954         for (p = r_glsl_permutationhash[mode][hashindex];p;p = p->hashnext)
955         {
956                 if (p->mode == mode && p->permutation == permutation)
957                 {
958                         //if (hashdepth > 10)
959                         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
960                         return p;
961                 }
962                 //hashdepth++;
963         }
964         p = (r_glsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_glsl_permutationarray);
965         p->mode = mode;
966         p->permutation = permutation;
967         p->hashnext = r_glsl_permutationhash[mode][hashindex];
968         r_glsl_permutationhash[mode][hashindex] = p;
969         //if (hashdepth > 10)
970         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
971         return p;
972 }
973
974 static char *R_ShaderStrCat(const char **strings)
975 {
976         char *string, *s;
977         const char **p = strings;
978         const char *t;
979         size_t len = 0;
980         for (p = strings;(t = *p);p++)
981                 len += strlen(t);
982         len++;
983         s = string = (char *)Mem_Alloc(r_main_mempool, len);
984         len = 0;
985         for (p = strings;(t = *p);p++)
986         {
987                 len = strlen(t);
988                 memcpy(s, t, len);
989                 s += len;
990         }
991         *s = 0;
992         return string;
993 }
994
995 static char *R_ShaderStrCat(const char **strings);
996 static void R_InitShaderModeInfo(void)
997 {
998         int i, language;
999         shadermodeinfo_t *modeinfo;
1000         // we have a bunch of things to compute that weren't calculated at engine compile time - all filenames should have a crc of the builtin strings to prevent accidental overrides (any customization must be updated to match engine)
1001         for (language = 0; language < SHADERLANGUAGE_COUNT; language++)
1002         {
1003                 for (i = 0; i < SHADERMODE_COUNT; i++)
1004                 {
1005                         char filename[MAX_QPATH];
1006                         modeinfo = &shadermodeinfo[language][i];
1007                         modeinfo->builtinstring = R_ShaderStrCat(modeinfo->builtinshaderstrings);
1008                         modeinfo->builtincrc = CRC_Block((const unsigned char *)modeinfo->builtinstring, strlen(modeinfo->builtinstring));
1009                         dpsnprintf(filename, sizeof(filename), "%s/%s_crc%i.%s", modeinfo->extension, modeinfo->sourcebasename, modeinfo->builtincrc, modeinfo->extension);
1010                         modeinfo->filename = Mem_strdup(r_main_mempool, filename);
1011                 }
1012         }
1013 }
1014
1015 static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qboolean printfromdisknotice, qboolean builtinonly)
1016 {
1017         char *shaderstring;
1018         // if the mode has no filename we have to return the builtin string
1019         if (builtinonly || !modeinfo->filename)
1020                 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1021         // note that FS_LoadFile appends a 0 byte to make it a valid string
1022         shaderstring = (char *)FS_LoadFile(modeinfo->filename, r_main_mempool, false, NULL);
1023         if (shaderstring)
1024         {
1025                 if (printfromdisknotice)
1026                         Con_DPrintf("Loading shaders from file %s...\n", modeinfo->filename);
1027                 return shaderstring;
1028         }
1029         // fall back to builtinstring
1030         return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1031 }
1032
1033 static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, dpuint64 permutation)
1034 {
1035         int i;
1036         int ubibind;
1037         int sampler;
1038         shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode];
1039         char *sourcestring;
1040         char permutationname[256];
1041         int vertstrings_count = 0;
1042         int geomstrings_count = 0;
1043         int fragstrings_count = 0;
1044         const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1045         const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1046         const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1047
1048         if (p->compiled)
1049                 return;
1050         p->compiled = true;
1051         p->program = 0;
1052
1053         permutationname[0] = 0;
1054         sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false);
1055
1056         strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
1057
1058         // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object)
1059         if(vid.support.glshaderversion >= 140)
1060         {
1061                 vertstrings_list[vertstrings_count++] = "#version 140\n";
1062                 geomstrings_list[geomstrings_count++] = "#version 140\n";
1063                 fragstrings_list[fragstrings_count++] = "#version 140\n";
1064                 vertstrings_list[vertstrings_count++] = "#define GLSL140\n";
1065                 geomstrings_list[geomstrings_count++] = "#define GLSL140\n";
1066                 fragstrings_list[fragstrings_count++] = "#define GLSL140\n";
1067         }
1068         // if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad)
1069         else if(vid.support.glshaderversion >= 130)
1070         {
1071                 vertstrings_list[vertstrings_count++] = "#version 130\n";
1072                 geomstrings_list[geomstrings_count++] = "#version 130\n";
1073                 fragstrings_list[fragstrings_count++] = "#version 130\n";
1074                 vertstrings_list[vertstrings_count++] = "#define GLSL130\n";
1075                 geomstrings_list[geomstrings_count++] = "#define GLSL130\n";
1076                 fragstrings_list[fragstrings_count++] = "#define GLSL130\n";
1077         }
1078         // if we can do #version 120, we should (this adds the invariant keyword)
1079         else if(vid.support.glshaderversion >= 120)
1080         {
1081                 vertstrings_list[vertstrings_count++] = "#version 120\n";
1082                 geomstrings_list[geomstrings_count++] = "#version 120\n";
1083                 fragstrings_list[fragstrings_count++] = "#version 120\n";
1084                 vertstrings_list[vertstrings_count++] = "#define GLSL120\n";
1085                 geomstrings_list[geomstrings_count++] = "#define GLSL120\n";
1086                 fragstrings_list[fragstrings_count++] = "#define GLSL120\n";
1087         }
1088         // GLES also adds several things from GLSL120
1089         switch(vid.renderpath)
1090         {
1091         case RENDERPATH_GLES2:
1092                 vertstrings_list[vertstrings_count++] = "#define GLES\n";
1093                 geomstrings_list[geomstrings_count++] = "#define GLES\n";
1094                 fragstrings_list[fragstrings_count++] = "#define GLES\n";
1095                 break;
1096         default:
1097                 break;
1098         }
1099
1100         // the first pretext is which type of shader to compile as
1101         // (later these will all be bound together as a program object)
1102         vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
1103         geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
1104         fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
1105
1106         // the second pretext is the mode (for example a light source)
1107         vertstrings_list[vertstrings_count++] = modeinfo->pretext;
1108         geomstrings_list[geomstrings_count++] = modeinfo->pretext;
1109         fragstrings_list[fragstrings_count++] = modeinfo->pretext;
1110         strlcat(permutationname, modeinfo->name, sizeof(permutationname));
1111
1112         // now add all the permutation pretexts
1113         for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1114         {
1115                 if (permutation & (1ll<<i))
1116                 {
1117                         vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
1118                         geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
1119                         fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
1120                         strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
1121                 }
1122                 else
1123                 {
1124                         // keep line numbers correct
1125                         vertstrings_list[vertstrings_count++] = "\n";
1126                         geomstrings_list[geomstrings_count++] = "\n";
1127                         fragstrings_list[fragstrings_count++] = "\n";
1128                 }
1129         }
1130
1131         // add static parms
1132         R_CompileShader_AddStaticParms(mode, permutation);
1133         memcpy((char *)(vertstrings_list + vertstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1134         vertstrings_count += shaderstaticparms_count;
1135         memcpy((char *)(geomstrings_list + geomstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1136         geomstrings_count += shaderstaticparms_count;
1137         memcpy((char *)(fragstrings_list + fragstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1138         fragstrings_count += shaderstaticparms_count;
1139
1140         // now append the shader text itself
1141         vertstrings_list[vertstrings_count++] = sourcestring;
1142         geomstrings_list[geomstrings_count++] = sourcestring;
1143         fragstrings_list[fragstrings_count++] = sourcestring;
1144
1145         // we don't currently use geometry shaders for anything, so just empty the list
1146         geomstrings_count = 0;
1147
1148         // compile the shader program
1149         if (vertstrings_count + geomstrings_count + fragstrings_count)
1150                 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1151         if (p->program)
1152         {
1153                 CHECKGLERROR
1154                 qglUseProgram(p->program);CHECKGLERROR
1155                 // look up all the uniform variable names we care about, so we don't
1156                 // have to look them up every time we set them
1157
1158 #if 0
1159                 // debugging aid
1160                 {
1161                         GLint activeuniformindex = 0;
1162                         GLint numactiveuniforms = 0;
1163                         char uniformname[128];
1164                         GLsizei uniformnamelength = 0;
1165                         GLint uniformsize = 0;
1166                         GLenum uniformtype = 0;
1167                         memset(uniformname, 0, sizeof(uniformname));
1168                         qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms);
1169                         Con_Printf("Shader has %i uniforms\n", numactiveuniforms);
1170                         for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++)
1171                         {
1172                                 qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname);
1173                                 Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype);
1174                         }
1175                 }
1176 #endif
1177
1178                 p->loc_Texture_First              = qglGetUniformLocation(p->program, "Texture_First");
1179                 p->loc_Texture_Second             = qglGetUniformLocation(p->program, "Texture_Second");
1180                 p->loc_Texture_GammaRamps         = qglGetUniformLocation(p->program, "Texture_GammaRamps");
1181                 p->loc_Texture_Normal             = qglGetUniformLocation(p->program, "Texture_Normal");
1182                 p->loc_Texture_Color              = qglGetUniformLocation(p->program, "Texture_Color");
1183                 p->loc_Texture_Gloss              = qglGetUniformLocation(p->program, "Texture_Gloss");
1184                 p->loc_Texture_Glow               = qglGetUniformLocation(p->program, "Texture_Glow");
1185                 p->loc_Texture_SecondaryNormal    = qglGetUniformLocation(p->program, "Texture_SecondaryNormal");
1186                 p->loc_Texture_SecondaryColor     = qglGetUniformLocation(p->program, "Texture_SecondaryColor");
1187                 p->loc_Texture_SecondaryGloss     = qglGetUniformLocation(p->program, "Texture_SecondaryGloss");
1188                 p->loc_Texture_SecondaryGlow      = qglGetUniformLocation(p->program, "Texture_SecondaryGlow");
1189                 p->loc_Texture_Pants              = qglGetUniformLocation(p->program, "Texture_Pants");
1190                 p->loc_Texture_Shirt              = qglGetUniformLocation(p->program, "Texture_Shirt");
1191                 p->loc_Texture_FogHeightTexture   = qglGetUniformLocation(p->program, "Texture_FogHeightTexture");
1192                 p->loc_Texture_FogMask            = qglGetUniformLocation(p->program, "Texture_FogMask");
1193                 p->loc_Texture_Lightmap           = qglGetUniformLocation(p->program, "Texture_Lightmap");
1194                 p->loc_Texture_Deluxemap          = qglGetUniformLocation(p->program, "Texture_Deluxemap");
1195                 p->loc_Texture_Attenuation        = qglGetUniformLocation(p->program, "Texture_Attenuation");
1196                 p->loc_Texture_Cube               = qglGetUniformLocation(p->program, "Texture_Cube");
1197                 p->loc_Texture_Refraction         = qglGetUniformLocation(p->program, "Texture_Refraction");
1198                 p->loc_Texture_Reflection         = qglGetUniformLocation(p->program, "Texture_Reflection");
1199                 p->loc_Texture_ShadowMap2D        = qglGetUniformLocation(p->program, "Texture_ShadowMap2D");
1200                 p->loc_Texture_CubeProjection     = qglGetUniformLocation(p->program, "Texture_CubeProjection");
1201                 p->loc_Texture_ScreenNormalMap    = qglGetUniformLocation(p->program, "Texture_ScreenNormalMap");
1202                 p->loc_Texture_ScreenDiffuse      = qglGetUniformLocation(p->program, "Texture_ScreenDiffuse");
1203                 p->loc_Texture_ScreenSpecular     = qglGetUniformLocation(p->program, "Texture_ScreenSpecular");
1204                 p->loc_Texture_ReflectMask        = qglGetUniformLocation(p->program, "Texture_ReflectMask");
1205                 p->loc_Texture_ReflectCube        = qglGetUniformLocation(p->program, "Texture_ReflectCube");
1206                 p->loc_Texture_BounceGrid         = qglGetUniformLocation(p->program, "Texture_BounceGrid");
1207                 p->loc_Alpha                      = qglGetUniformLocation(p->program, "Alpha");
1208                 p->loc_BloomBlur_Parameters       = qglGetUniformLocation(p->program, "BloomBlur_Parameters");
1209                 p->loc_ClientTime                 = qglGetUniformLocation(p->program, "ClientTime");
1210                 p->loc_Color_Ambient              = qglGetUniformLocation(p->program, "Color_Ambient");
1211                 p->loc_Color_Diffuse              = qglGetUniformLocation(p->program, "Color_Diffuse");
1212                 p->loc_Color_Specular             = qglGetUniformLocation(p->program, "Color_Specular");
1213                 p->loc_Color_Glow                 = qglGetUniformLocation(p->program, "Color_Glow");
1214                 p->loc_Color_Pants                = qglGetUniformLocation(p->program, "Color_Pants");
1215                 p->loc_Color_Shirt                = qglGetUniformLocation(p->program, "Color_Shirt");
1216                 p->loc_DeferredColor_Ambient      = qglGetUniformLocation(p->program, "DeferredColor_Ambient");
1217                 p->loc_DeferredColor_Diffuse      = qglGetUniformLocation(p->program, "DeferredColor_Diffuse");
1218                 p->loc_DeferredColor_Specular     = qglGetUniformLocation(p->program, "DeferredColor_Specular");
1219                 p->loc_DeferredMod_Diffuse        = qglGetUniformLocation(p->program, "DeferredMod_Diffuse");
1220                 p->loc_DeferredMod_Specular       = qglGetUniformLocation(p->program, "DeferredMod_Specular");
1221                 p->loc_DistortScaleRefractReflect = qglGetUniformLocation(p->program, "DistortScaleRefractReflect");
1222                 p->loc_EyePosition                = qglGetUniformLocation(p->program, "EyePosition");
1223                 p->loc_FogColor                   = qglGetUniformLocation(p->program, "FogColor");
1224                 p->loc_FogHeightFade              = qglGetUniformLocation(p->program, "FogHeightFade");
1225                 p->loc_FogPlane                   = qglGetUniformLocation(p->program, "FogPlane");
1226                 p->loc_FogPlaneViewDist           = qglGetUniformLocation(p->program, "FogPlaneViewDist");
1227                 p->loc_FogRangeRecip              = qglGetUniformLocation(p->program, "FogRangeRecip");
1228                 p->loc_LightColor                 = qglGetUniformLocation(p->program, "LightColor");
1229                 p->loc_LightDir                   = qglGetUniformLocation(p->program, "LightDir");
1230                 p->loc_LightPosition              = qglGetUniformLocation(p->program, "LightPosition");
1231                 p->loc_OffsetMapping_ScaleSteps   = qglGetUniformLocation(p->program, "OffsetMapping_ScaleSteps");
1232                 p->loc_OffsetMapping_LodDistance  = qglGetUniformLocation(p->program, "OffsetMapping_LodDistance");
1233                 p->loc_OffsetMapping_Bias         = qglGetUniformLocation(p->program, "OffsetMapping_Bias");
1234                 p->loc_PixelSize                  = qglGetUniformLocation(p->program, "PixelSize");
1235                 p->loc_ReflectColor               = qglGetUniformLocation(p->program, "ReflectColor");
1236                 p->loc_ReflectFactor              = qglGetUniformLocation(p->program, "ReflectFactor");
1237                 p->loc_ReflectOffset              = qglGetUniformLocation(p->program, "ReflectOffset");
1238                 p->loc_RefractColor               = qglGetUniformLocation(p->program, "RefractColor");
1239                 p->loc_Saturation                 = qglGetUniformLocation(p->program, "Saturation");
1240                 p->loc_ScreenCenterRefractReflect = qglGetUniformLocation(p->program, "ScreenCenterRefractReflect");
1241                 p->loc_ScreenScaleRefractReflect  = qglGetUniformLocation(p->program, "ScreenScaleRefractReflect");
1242                 p->loc_ScreenToDepth              = qglGetUniformLocation(p->program, "ScreenToDepth");
1243                 p->loc_ShadowMap_Parameters       = qglGetUniformLocation(p->program, "ShadowMap_Parameters");
1244                 p->loc_ShadowMap_TextureScale     = qglGetUniformLocation(p->program, "ShadowMap_TextureScale");
1245                 p->loc_SpecularPower              = qglGetUniformLocation(p->program, "SpecularPower");
1246                 p->loc_UserVec1                   = qglGetUniformLocation(p->program, "UserVec1");
1247                 p->loc_UserVec2                   = qglGetUniformLocation(p->program, "UserVec2");
1248                 p->loc_UserVec3                   = qglGetUniformLocation(p->program, "UserVec3");
1249                 p->loc_UserVec4                   = qglGetUniformLocation(p->program, "UserVec4");
1250                 p->loc_ViewTintColor              = qglGetUniformLocation(p->program, "ViewTintColor");
1251                 p->loc_ViewToLight                = qglGetUniformLocation(p->program, "ViewToLight");
1252                 p->loc_ModelToLight               = qglGetUniformLocation(p->program, "ModelToLight");
1253                 p->loc_TexMatrix                  = qglGetUniformLocation(p->program, "TexMatrix");
1254                 p->loc_BackgroundTexMatrix        = qglGetUniformLocation(p->program, "BackgroundTexMatrix");
1255                 p->loc_ModelViewMatrix            = qglGetUniformLocation(p->program, "ModelViewMatrix");
1256                 p->loc_ModelViewProjectionMatrix  = qglGetUniformLocation(p->program, "ModelViewProjectionMatrix");
1257                 p->loc_PixelToScreenTexCoord      = qglGetUniformLocation(p->program, "PixelToScreenTexCoord");
1258                 p->loc_ModelToReflectCube         = qglGetUniformLocation(p->program, "ModelToReflectCube");
1259                 p->loc_ShadowMapMatrix            = qglGetUniformLocation(p->program, "ShadowMapMatrix");
1260                 p->loc_BloomColorSubtract         = qglGetUniformLocation(p->program, "BloomColorSubtract");
1261                 p->loc_NormalmapScrollBlend       = qglGetUniformLocation(p->program, "NormalmapScrollBlend");
1262                 p->loc_BounceGridMatrix           = qglGetUniformLocation(p->program, "BounceGridMatrix");
1263                 p->loc_BounceGridIntensity        = qglGetUniformLocation(p->program, "BounceGridIntensity");
1264                 // initialize the samplers to refer to the texture units we use
1265                 p->tex_Texture_First = -1;
1266                 p->tex_Texture_Second = -1;
1267                 p->tex_Texture_GammaRamps = -1;
1268                 p->tex_Texture_Normal = -1;
1269                 p->tex_Texture_Color = -1;
1270                 p->tex_Texture_Gloss = -1;
1271                 p->tex_Texture_Glow = -1;
1272                 p->tex_Texture_SecondaryNormal = -1;
1273                 p->tex_Texture_SecondaryColor = -1;
1274                 p->tex_Texture_SecondaryGloss = -1;
1275                 p->tex_Texture_SecondaryGlow = -1;
1276                 p->tex_Texture_Pants = -1;
1277                 p->tex_Texture_Shirt = -1;
1278                 p->tex_Texture_FogHeightTexture = -1;
1279                 p->tex_Texture_FogMask = -1;
1280                 p->tex_Texture_Lightmap = -1;
1281                 p->tex_Texture_Deluxemap = -1;
1282                 p->tex_Texture_Attenuation = -1;
1283                 p->tex_Texture_Cube = -1;
1284                 p->tex_Texture_Refraction = -1;
1285                 p->tex_Texture_Reflection = -1;
1286                 p->tex_Texture_ShadowMap2D = -1;
1287                 p->tex_Texture_CubeProjection = -1;
1288                 p->tex_Texture_ScreenNormalMap = -1;
1289                 p->tex_Texture_ScreenDiffuse = -1;
1290                 p->tex_Texture_ScreenSpecular = -1;
1291                 p->tex_Texture_ReflectMask = -1;
1292                 p->tex_Texture_ReflectCube = -1;
1293                 p->tex_Texture_BounceGrid = -1;
1294                 // bind the texture samplers in use
1295                 sampler = 0;
1296                 if (p->loc_Texture_First           >= 0) {p->tex_Texture_First            = sampler;qglUniform1i(p->loc_Texture_First           , sampler);sampler++;}
1297                 if (p->loc_Texture_Second          >= 0) {p->tex_Texture_Second           = sampler;qglUniform1i(p->loc_Texture_Second          , sampler);sampler++;}
1298                 if (p->loc_Texture_GammaRamps      >= 0) {p->tex_Texture_GammaRamps       = sampler;qglUniform1i(p->loc_Texture_GammaRamps      , sampler);sampler++;}
1299                 if (p->loc_Texture_Normal          >= 0) {p->tex_Texture_Normal           = sampler;qglUniform1i(p->loc_Texture_Normal          , sampler);sampler++;}
1300                 if (p->loc_Texture_Color           >= 0) {p->tex_Texture_Color            = sampler;qglUniform1i(p->loc_Texture_Color           , sampler);sampler++;}
1301                 if (p->loc_Texture_Gloss           >= 0) {p->tex_Texture_Gloss            = sampler;qglUniform1i(p->loc_Texture_Gloss           , sampler);sampler++;}
1302                 if (p->loc_Texture_Glow            >= 0) {p->tex_Texture_Glow             = sampler;qglUniform1i(p->loc_Texture_Glow            , sampler);sampler++;}
1303                 if (p->loc_Texture_SecondaryNormal >= 0) {p->tex_Texture_SecondaryNormal  = sampler;qglUniform1i(p->loc_Texture_SecondaryNormal , sampler);sampler++;}
1304                 if (p->loc_Texture_SecondaryColor  >= 0) {p->tex_Texture_SecondaryColor   = sampler;qglUniform1i(p->loc_Texture_SecondaryColor  , sampler);sampler++;}
1305                 if (p->loc_Texture_SecondaryGloss  >= 0) {p->tex_Texture_SecondaryGloss   = sampler;qglUniform1i(p->loc_Texture_SecondaryGloss  , sampler);sampler++;}
1306                 if (p->loc_Texture_SecondaryGlow   >= 0) {p->tex_Texture_SecondaryGlow    = sampler;qglUniform1i(p->loc_Texture_SecondaryGlow   , sampler);sampler++;}
1307                 if (p->loc_Texture_Pants           >= 0) {p->tex_Texture_Pants            = sampler;qglUniform1i(p->loc_Texture_Pants           , sampler);sampler++;}
1308                 if (p->loc_Texture_Shirt           >= 0) {p->tex_Texture_Shirt            = sampler;qglUniform1i(p->loc_Texture_Shirt           , sampler);sampler++;}
1309                 if (p->loc_Texture_FogHeightTexture>= 0) {p->tex_Texture_FogHeightTexture = sampler;qglUniform1i(p->loc_Texture_FogHeightTexture, sampler);sampler++;}
1310                 if (p->loc_Texture_FogMask         >= 0) {p->tex_Texture_FogMask          = sampler;qglUniform1i(p->loc_Texture_FogMask         , sampler);sampler++;}
1311                 if (p->loc_Texture_Lightmap        >= 0) {p->tex_Texture_Lightmap         = sampler;qglUniform1i(p->loc_Texture_Lightmap        , sampler);sampler++;}
1312                 if (p->loc_Texture_Deluxemap       >= 0) {p->tex_Texture_Deluxemap        = sampler;qglUniform1i(p->loc_Texture_Deluxemap       , sampler);sampler++;}
1313                 if (p->loc_Texture_Attenuation     >= 0) {p->tex_Texture_Attenuation      = sampler;qglUniform1i(p->loc_Texture_Attenuation     , sampler);sampler++;}
1314                 if (p->loc_Texture_Cube            >= 0) {p->tex_Texture_Cube             = sampler;qglUniform1i(p->loc_Texture_Cube            , sampler);sampler++;}
1315                 if (p->loc_Texture_Refraction      >= 0) {p->tex_Texture_Refraction       = sampler;qglUniform1i(p->loc_Texture_Refraction      , sampler);sampler++;}
1316                 if (p->loc_Texture_Reflection      >= 0) {p->tex_Texture_Reflection       = sampler;qglUniform1i(p->loc_Texture_Reflection      , sampler);sampler++;}
1317                 if (p->loc_Texture_ShadowMap2D     >= 0) {p->tex_Texture_ShadowMap2D      = sampler;qglUniform1i(p->loc_Texture_ShadowMap2D     , sampler);sampler++;}
1318                 if (p->loc_Texture_CubeProjection  >= 0) {p->tex_Texture_CubeProjection   = sampler;qglUniform1i(p->loc_Texture_CubeProjection  , sampler);sampler++;}
1319                 if (p->loc_Texture_ScreenNormalMap >= 0) {p->tex_Texture_ScreenNormalMap  = sampler;qglUniform1i(p->loc_Texture_ScreenNormalMap , sampler);sampler++;}
1320                 if (p->loc_Texture_ScreenDiffuse   >= 0) {p->tex_Texture_ScreenDiffuse    = sampler;qglUniform1i(p->loc_Texture_ScreenDiffuse   , sampler);sampler++;}
1321                 if (p->loc_Texture_ScreenSpecular  >= 0) {p->tex_Texture_ScreenSpecular   = sampler;qglUniform1i(p->loc_Texture_ScreenSpecular  , sampler);sampler++;}
1322                 if (p->loc_Texture_ReflectMask     >= 0) {p->tex_Texture_ReflectMask      = sampler;qglUniform1i(p->loc_Texture_ReflectMask     , sampler);sampler++;}
1323                 if (p->loc_Texture_ReflectCube     >= 0) {p->tex_Texture_ReflectCube      = sampler;qglUniform1i(p->loc_Texture_ReflectCube     , sampler);sampler++;}
1324                 if (p->loc_Texture_BounceGrid      >= 0) {p->tex_Texture_BounceGrid       = sampler;qglUniform1i(p->loc_Texture_BounceGrid      , sampler);sampler++;}
1325                 // get the uniform block indices so we can bind them
1326                 p->ubiloc_Skeletal_Transform12_UniformBlock = -1;
1327 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1328                 p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
1329 #endif
1330                 // clear the uniform block bindings
1331                 p->ubibind_Skeletal_Transform12_UniformBlock = -1;
1332                 // bind the uniform blocks in use
1333                 ubibind = 0;
1334 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1335                 if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;}
1336 #endif
1337                 // we're done compiling and setting up the shader, at least until it is used
1338                 CHECKGLERROR
1339                 Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler);
1340         }
1341         else
1342                 Con_Printf("^1GLSL shader %s failed!  some features may not work properly.\n", permutationname);
1343
1344         // free the strings
1345         if (sourcestring)
1346                 Mem_Free(sourcestring);
1347 }
1348
1349 static void R_SetupShader_SetPermutationGLSL(unsigned int mode, dpuint64 permutation)
1350 {
1351         r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation);
1352         if (r_glsl_permutation != perm)
1353         {
1354                 r_glsl_permutation = perm;
1355                 if (!r_glsl_permutation->program)
1356                 {
1357                         if (!r_glsl_permutation->compiled)
1358                         {
1359                                 Con_DPrintf("Compiling shader mode %u permutation %llx\n", mode, permutation);
1360                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1361                         }
1362                         if (!r_glsl_permutation->program)
1363                         {
1364                                 // remove features until we find a valid permutation
1365                                 int i;
1366                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1367                                 {
1368                                         // reduce i more quickly whenever it would not remove any bits
1369                                         dpuint64 j = 1ll<<(SHADERPERMUTATION_COUNT-1-i);
1370                                         if (!(permutation & j))
1371                                                 continue;
1372                                         permutation -= j;
1373                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1374                                         if (!r_glsl_permutation->compiled)
1375                                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1376                                         if (r_glsl_permutation->program)
1377                                                 break;
1378                                 }
1379                                 if (i >= SHADERPERMUTATION_COUNT)
1380                                 {
1381                                         //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext);
1382                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1383                                         qglUseProgram(0);CHECKGLERROR
1384                                         return; // no bit left to clear, entire mode is broken
1385                                 }
1386                         }
1387                 }
1388                 CHECKGLERROR
1389                 qglUseProgram(r_glsl_permutation->program);CHECKGLERROR
1390         }
1391         if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
1392         if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
1393         if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time);
1394         CHECKGLERROR
1395 }
1396
1397 void R_GLSL_Restart_f(cmd_state_t *cmd)
1398 {
1399         unsigned int i, limit;
1400         switch(vid.renderpath)
1401         {
1402         case RENDERPATH_GL32:
1403         case RENDERPATH_GLES2:
1404                 {
1405                         r_glsl_permutation_t *p;
1406                         r_glsl_permutation = NULL;
1407                         limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
1408                         for (i = 0;i < limit;i++)
1409                         {
1410                                 if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
1411                                 {
1412                                         GL_Backend_FreeProgram(p->program);
1413                                         Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
1414                                 }
1415                         }
1416                         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
1417                 }
1418                 break;
1419         }
1420 }
1421
1422 static void R_GLSL_DumpShader_f(cmd_state_t *cmd)
1423 {
1424         int i, language, mode, dupe;
1425         char *text;
1426         shadermodeinfo_t *modeinfo;
1427         qfile_t *file;
1428
1429         for (language = 0;language < SHADERLANGUAGE_COUNT;language++)
1430         {
1431                 modeinfo = shadermodeinfo[language];
1432                 for (mode = 0;mode < SHADERMODE_COUNT;mode++)
1433                 {
1434                         // don't dump the same file multiple times (most or all shaders come from the same file)
1435                         for (dupe = mode - 1;dupe >= 0;dupe--)
1436                                 if (!strcmp(modeinfo[mode].filename, modeinfo[dupe].filename))
1437                                         break;
1438                         if (dupe >= 0)
1439                                 continue;
1440                         text = modeinfo[mode].builtinstring;
1441                         if (!text)
1442                                 continue;
1443                         file = FS_OpenRealFile(modeinfo[mode].filename, "w", false);
1444                         if (file)
1445                         {
1446                                 FS_Print(file, "/* The engine may define the following macros:\n");
1447                                 FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
1448                                 for (i = 0;i < SHADERMODE_COUNT;i++)
1449                                         FS_Print(file, modeinfo[i].pretext);
1450                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1451                                         FS_Print(file, shaderpermutationinfo[i].pretext);
1452                                 FS_Print(file, "*/\n");
1453                                 FS_Print(file, text);
1454                                 FS_Close(file);
1455                                 Con_Printf("%s written\n", modeinfo[mode].filename);
1456                         }
1457                         else
1458                                 Con_Printf("failed to write to %s\n", modeinfo[mode].filename);
1459                 }
1460         }
1461 }
1462
1463 void R_SetupShader_Generic(rtexture_t *t, qboolean usegamma, qboolean notrippy, qboolean suppresstexalpha)
1464 {
1465         dpuint64 permutation = 0;
1466         if (r_trippy.integer && !notrippy)
1467                 permutation |= SHADERPERMUTATION_TRIPPY;
1468         permutation |= SHADERPERMUTATION_VIEWTINT;
1469         if (t)
1470                 permutation |= SHADERPERMUTATION_DIFFUSE;
1471         if (usegamma && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
1472                 permutation |= SHADERPERMUTATION_GAMMARAMPS;
1473         if (suppresstexalpha)
1474                 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1475         if (vid.allowalphatocoverage)
1476                 GL_AlphaToCoverage(false);
1477         switch (vid.renderpath)
1478         {
1479         case RENDERPATH_GL32:
1480         case RENDERPATH_GLES2:
1481                 R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation);
1482                 if (r_glsl_permutation->tex_Texture_First >= 0)
1483                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First, t);
1484                 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0)
1485                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps);
1486                 break;
1487         }
1488 }
1489
1490 void R_SetupShader_Generic_NoTexture(qboolean usegamma, qboolean notrippy)
1491 {
1492         R_SetupShader_Generic(NULL, usegamma, notrippy, false);
1493 }
1494
1495 void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb, qboolean skeletal)
1496 {
1497         dpuint64 permutation = 0;
1498         if (r_trippy.integer && !notrippy)
1499                 permutation |= SHADERPERMUTATION_TRIPPY;
1500         if (depthrgb)
1501                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1502         if (skeletal)
1503                 permutation |= SHADERPERMUTATION_SKELETAL;
1504
1505         if (vid.allowalphatocoverage)
1506                 GL_AlphaToCoverage(false);
1507         switch (vid.renderpath)
1508         {
1509         case RENDERPATH_GL32:
1510         case RENDERPATH_GLES2:
1511                 R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
1512 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1513                 if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
1514 #endif
1515                 break;
1516         }
1517 }
1518
1519 #define BLENDFUNC_ALLOWS_COLORMOD      1
1520 #define BLENDFUNC_ALLOWS_FOG           2
1521 #define BLENDFUNC_ALLOWS_FOG_HACK0     4
1522 #define BLENDFUNC_ALLOWS_FOG_HACKALPHA 8
1523 #define BLENDFUNC_ALLOWS_ANYFOG        (BLENDFUNC_ALLOWS_FOG | BLENDFUNC_ALLOWS_FOG_HACK0 | BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1524 static int R_BlendFuncFlags(int src, int dst)
1525 {
1526         int r = 0;
1527
1528         // a blendfunc allows colormod if:
1529         // a) it can never keep the destination pixel invariant, or
1530         // b) it can keep the destination pixel invariant, and still can do so if colormodded
1531         // this is to prevent unintended side effects from colormod
1532
1533         // a blendfunc allows fog if:
1534         // blend(fog(src), fog(dst)) == fog(blend(src, dst))
1535         // this is to prevent unintended side effects from fog
1536
1537         // these checks are the output of fogeval.pl
1538
1539         r |= BLENDFUNC_ALLOWS_COLORMOD;
1540         if(src == GL_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1541         if(src == GL_DST_ALPHA && dst == GL_ONE_MINUS_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1542         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1543         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1544         if(src == GL_DST_COLOR && dst == GL_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1545         if(src == GL_DST_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1546         if(src == GL_DST_COLOR && dst == GL_ZERO) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1547         if(src == GL_ONE && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1548         if(src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG_HACKALPHA;
1549         if(src == GL_ONE && dst == GL_ZERO) r |= BLENDFUNC_ALLOWS_FOG;
1550         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1551         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1552         if(src == GL_ONE_MINUS_DST_COLOR && dst == GL_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1553         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1554         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1555         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1556         if(src == GL_ONE_MINUS_SRC_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1557         if(src == GL_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1558         if(src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1559         if(src == GL_ZERO && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG;
1560         if(src == GL_ZERO && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1561
1562         return r;
1563 }
1564
1565 void R_SetupShader_Surface(const float rtlightambient[3], const float rtlightdiffuse[3], const float rtlightspecular[3], rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist, void *surfacewaterplane, qboolean notrippy)
1566 {
1567         // select a permutation of the lighting shader appropriate to this
1568         // combination of texture, entity, light source, and fogging, only use the
1569         // minimum features necessary to avoid wasting rendering time in the
1570         // fragment shader on features that are not being used
1571         dpuint64 permutation = 0;
1572         unsigned int mode = 0;
1573         int blendfuncflags;
1574         texture_t *t = rsurface.texture;
1575         float m16f[16];
1576         matrix4x4_t tempmatrix;
1577         r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
1578         if (r_trippy.integer && !notrippy)
1579                 permutation |= SHADERPERMUTATION_TRIPPY;
1580         if (t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1581                 permutation |= SHADERPERMUTATION_ALPHAKILL;
1582         if (t->currentmaterialflags & MATERIALFLAG_OCCLUDE)
1583                 permutation |= SHADERPERMUTATION_OCCLUDE;
1584         if (t->r_water_waterscroll[0] && t->r_water_waterscroll[1])
1585                 permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
1586         if (rsurfacepass == RSURFPASS_BACKGROUND)
1587         {
1588                 // distorted background
1589                 if (t->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1590                 {
1591                         mode = SHADERMODE_WATER;
1592                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1593                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1594                         if((r_wateralpha.value < 1) && (t->currentmaterialflags & MATERIALFLAG_WATERALPHA))
1595                         {
1596                                 // this is the right thing to do for wateralpha
1597                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1598                                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1599                         }
1600                         else
1601                         {
1602                                 // this is the right thing to do for entity alpha
1603                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1604                                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1605                         }
1606                 }
1607                 else if (t->currentmaterialflags & MATERIALFLAG_REFRACTION)
1608                 {
1609                         mode = SHADERMODE_REFRACTION;
1610                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1611                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1612                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1613                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1614                 }
1615                 else
1616                 {
1617                         mode = SHADERMODE_GENERIC;
1618                         permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL;
1619                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1620                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1621                 }
1622                 if (vid.allowalphatocoverage)
1623                         GL_AlphaToCoverage(false);
1624         }
1625         else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
1626         {
1627                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1628                 {
1629                         switch(t->offsetmapping)
1630                         {
1631                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1632                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1633                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1634                         case OFFSETMAPPING_OFF: break;
1635                         }
1636                 }
1637                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1638                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1639                 // normalmap (deferred prepass), may use alpha test on diffuse
1640                 mode = SHADERMODE_DEFERREDGEOMETRY;
1641                 GL_BlendFunc(GL_ONE, GL_ZERO);
1642                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1643                 if (vid.allowalphatocoverage)
1644                         GL_AlphaToCoverage(false);
1645         }
1646         else if (rsurfacepass == RSURFPASS_RTLIGHT)
1647         {
1648                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1649                 {
1650                         switch(t->offsetmapping)
1651                         {
1652                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1653                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1654                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1655                         case OFFSETMAPPING_OFF: break;
1656                         }
1657                 }
1658                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1659                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1660                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1661                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1662                 // light source
1663                 mode = SHADERMODE_LIGHTSOURCE;
1664                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1665                         permutation |= SHADERPERMUTATION_CUBEFILTER;
1666                 if (VectorLength2(rtlightdiffuse) > 0)
1667                         permutation |= SHADERPERMUTATION_DIFFUSE;
1668                 if (VectorLength2(rtlightspecular) > 0)
1669                         permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1670                 if (r_refdef.fogenabled)
1671                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1672                 if (t->colormapping)
1673                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1674                 if (r_shadow_usingshadowmap2d)
1675                 {
1676                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1677                         if(r_shadow_shadowmapvsdct)
1678                                 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
1679
1680                         if (r_shadow_shadowmap2ddepthbuffer)
1681                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1682                 }
1683                 if (t->reflectmasktexture)
1684                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1685                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1686                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE);
1687                 if (vid.allowalphatocoverage)
1688                         GL_AlphaToCoverage(false);
1689         }
1690         else if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
1691         {
1692                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1693                 {
1694                         switch(t->offsetmapping)
1695                         {
1696                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1697                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1698                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1699                         case OFFSETMAPPING_OFF: break;
1700                         }
1701                 }
1702                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1703                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1704                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1705                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1706                 // directional model lighting
1707                 mode = SHADERMODE_LIGHTDIRECTION;
1708                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1709                         permutation |= SHADERPERMUTATION_GLOW;
1710                 if (VectorLength2(t->render_modellight_diffuse))
1711                         permutation |= SHADERPERMUTATION_DIFFUSE;
1712                 if (VectorLength2(t->render_modellight_specular) > 0)
1713                         permutation |= SHADERPERMUTATION_SPECULAR;
1714                 if (r_refdef.fogenabled)
1715                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1716                 if (t->colormapping)
1717                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1718                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1719                 {
1720                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1721                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1722
1723                         if (r_shadow_shadowmap2ddepthbuffer)
1724                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1725                 }
1726                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1727                         permutation |= SHADERPERMUTATION_REFLECTION;
1728                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1729                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1730                 if (t->reflectmasktexture)
1731                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1732                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1733                 {
1734                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1735                         if (r_shadow_bouncegrid_state.directional)
1736                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1737                 }
1738                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1739                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1740                 // when using alphatocoverage, we don't need alphakill
1741                 if (vid.allowalphatocoverage)
1742                 {
1743                         if (r_transparent_alphatocoverage.integer)
1744                         {
1745                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1746                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1747                         }
1748                         else
1749                                 GL_AlphaToCoverage(false);
1750                 }
1751         }
1752         else
1753         {
1754                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1755                 {
1756                         switch(t->offsetmapping)
1757                         {
1758                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1759                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1760                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1761                         case OFFSETMAPPING_OFF: break;
1762                         }
1763                 }
1764                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1765                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1766                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1767                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1768                 // lightmapped wall
1769                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1770                         permutation |= SHADERPERMUTATION_GLOW;
1771                 if (r_refdef.fogenabled)
1772                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1773                 if (t->colormapping)
1774                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1775                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1776                 {
1777                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1778                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1779
1780                         if (r_shadow_shadowmap2ddepthbuffer)
1781                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1782                 }
1783                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1784                         permutation |= SHADERPERMUTATION_REFLECTION;
1785                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1786                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1787                 if (t->reflectmasktexture)
1788                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1789                 if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
1790                 {
1791                         // deluxemapping (light direction texture)
1792                         if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace)
1793                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1794                         else
1795                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1796                         permutation |= SHADERPERMUTATION_DIFFUSE;
1797                         if (VectorLength2(t->render_lightmap_specular) > 0)
1798                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1799                 }
1800                 else if (r_glsl_deluxemapping.integer >= 2)
1801                 {
1802                         // fake deluxemapping (uniform light direction in tangentspace)
1803                         if (rsurface.uselightmaptexture)
1804                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP;
1805                         else
1806                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR;
1807                         permutation |= SHADERPERMUTATION_DIFFUSE;
1808                         if (VectorLength2(t->render_lightmap_specular) > 0)
1809                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1810                 }
1811                 else if (rsurface.uselightmaptexture)
1812                 {
1813                         // ordinary lightmapping (q1bsp, q3bsp)
1814                         mode = SHADERMODE_LIGHTMAP;
1815                 }
1816                 else
1817                 {
1818                         // ordinary vertex coloring (q3bsp)
1819                         mode = SHADERMODE_VERTEXCOLOR;
1820                 }
1821                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1822                 {
1823                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1824                         if (r_shadow_bouncegrid_state.directional)
1825                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1826                 }
1827                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1828                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1829                 // when using alphatocoverage, we don't need alphakill
1830                 if (vid.allowalphatocoverage)
1831                 {
1832                         if (r_transparent_alphatocoverage.integer)
1833                         {
1834                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1835                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1836                         }
1837                         else
1838                                 GL_AlphaToCoverage(false);
1839                 }
1840         }
1841         if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG))
1842                 permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE);
1843         if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1844                 permutation |= SHADERPERMUTATION_FOGALPHAHACK;
1845         switch(vid.renderpath)
1846         {
1847         case RENDERPATH_GL32:
1848         case RENDERPATH_GLES2:
1849                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | (rsurface.modellightmapcolor4f ? BATCHNEED_ARRAY_VERTEXCOLOR : 0) | BATCHNEED_ARRAY_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_ARRAY_LIGHTMAP : 0) | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
1850                 RSurf_UploadBuffersForBatch();
1851                 // this has to be after RSurf_PrepareVerticesForBatch
1852                 if (rsurface.batchskeletaltransform3x4buffer)
1853                         permutation |= SHADERPERMUTATION_SKELETAL;
1854                 R_SetupShader_SetPermutationGLSL(mode, permutation);
1855 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1856                 if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
1857 #endif
1858                 if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
1859                 if (mode == SHADERMODE_LIGHTSOURCE)
1860                 {
1861                         if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
1862                         if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1863                         if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1864                         if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
1865                         if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
1866                         if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
1867         
1868                         // additive passes are only darkened by fog, not tinted
1869                         if (r_glsl_permutation->loc_FogColor >= 0)
1870                                 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1871                         if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, t->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
1872                 }
1873                 else
1874                 {
1875                         if (mode == SHADERMODE_FLATCOLOR)
1876                         {
1877                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
1878                         }
1879                         else if (mode == SHADERMODE_LIGHTDIRECTION)
1880                         {
1881                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
1882                                 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_modellight_diffuse[0], t->render_modellight_diffuse[1], t->render_modellight_diffuse[2]);
1883                                 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_modellight_specular[0], t->render_modellight_specular[1], t->render_modellight_specular[2]);
1884                                 if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, t->render_rtlight_diffuse[0], t->render_rtlight_diffuse[1], t->render_rtlight_diffuse[2]);
1885                                 if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, t->render_rtlight_specular[0], t->render_rtlight_specular[1], t->render_rtlight_specular[2]);
1886                                 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1887                                 if (r_glsl_permutation->loc_LightDir >= 0) qglUniform3f(r_glsl_permutation->loc_LightDir, t->render_modellight_lightdir[0], t->render_modellight_lightdir[1], t->render_modellight_lightdir[2]);
1888                         }
1889                         else
1890                         {
1891                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_lightmap_ambient[0], t->render_lightmap_ambient[1], t->render_lightmap_ambient[2]);
1892                                 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_lightmap_diffuse[0], t->render_lightmap_diffuse[1], t->render_lightmap_diffuse[2]);
1893                                 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_lightmap_specular[0], t->render_lightmap_specular[1], t->render_lightmap_specular[2]);
1894                                 if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, t->render_rtlight_diffuse[0], t->render_rtlight_diffuse[1], t->render_rtlight_diffuse[2]);
1895                                 if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, t->render_rtlight_specular[0], t->render_rtlight_specular[1], t->render_rtlight_specular[2]);
1896                         }
1897                         // additive passes are only darkened by fog, not tinted
1898                         if (r_glsl_permutation->loc_FogColor >= 0)
1899                         {
1900                                 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
1901                                         qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1902                                 else
1903                                         qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1904                         }
1905                         if (r_glsl_permutation->loc_DistortScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_DistortScaleRefractReflect, r_water_refractdistort.value * t->refractfactor, r_water_refractdistort.value * t->refractfactor, r_water_reflectdistort.value * t->reflectfactor, r_water_reflectdistort.value * t->reflectfactor);
1906                         if (r_glsl_permutation->loc_ScreenScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenScaleRefractReflect, r_fb.water.screenscale[0], r_fb.water.screenscale[1], r_fb.water.screenscale[0], r_fb.water.screenscale[1]);
1907                         if (r_glsl_permutation->loc_ScreenCenterRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenCenterRefractReflect, r_fb.water.screencenter[0], r_fb.water.screencenter[1], r_fb.water.screencenter[0], r_fb.water.screencenter[1]);
1908                         if (r_glsl_permutation->loc_RefractColor >= 0) qglUniform4f(r_glsl_permutation->loc_RefractColor, t->refractcolor4f[0], t->refractcolor4f[1], t->refractcolor4f[2], t->refractcolor4f[3] * t->currentalpha);
1909                         if (r_glsl_permutation->loc_ReflectColor >= 0) qglUniform4f(r_glsl_permutation->loc_ReflectColor, t->reflectcolor4f[0], t->reflectcolor4f[1], t->reflectcolor4f[2], t->reflectcolor4f[3] * t->currentalpha);
1910                         if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, t->reflectmax - t->reflectmin);
1911                         if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, t->reflectmin);
1912                         if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, t->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
1913                         if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
1914                 }
1915                 if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
1916                 if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
1917                 if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
1918                 if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
1919                 {
1920                         if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_modelshadowmap_texturescale[0], r_shadow_modelshadowmap_texturescale[1], r_shadow_modelshadowmap_texturescale[2], r_shadow_modelshadowmap_texturescale[3]);
1921                         if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_modelshadowmap_parameters[0], r_shadow_modelshadowmap_parameters[1], r_shadow_modelshadowmap_parameters[2], r_shadow_modelshadowmap_parameters[3]);
1922                 }
1923                 else
1924                 {
1925                         if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
1926                         if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
1927                 }
1928
1929                 if (r_glsl_permutation->loc_Color_Glow >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Glow, t->render_glowmod[0], t->render_glowmod[1], t->render_glowmod[2]);
1930                 if (r_glsl_permutation->loc_Alpha >= 0) qglUniform1f(r_glsl_permutation->loc_Alpha, t->currentalpha * ((t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? t->r_water_wateralpha : 1));
1931                 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
1932                 if (r_glsl_permutation->loc_Color_Pants >= 0)
1933                 {
1934                         if (t->pantstexture)
1935                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
1936                         else
1937                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
1938                 }
1939                 if (r_glsl_permutation->loc_Color_Shirt >= 0)
1940                 {
1941                         if (t->shirttexture)
1942                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
1943                         else
1944                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
1945                 }
1946                 if (r_glsl_permutation->loc_FogPlane >= 0) qglUniform4f(r_glsl_permutation->loc_FogPlane, rsurface.fogplane[0], rsurface.fogplane[1], rsurface.fogplane[2], rsurface.fogplane[3]);
1947                 if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
1948                 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
1949                 if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
1950                 if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps,
1951                                 r_glsl_offsetmapping_scale.value*t->offsetscale,
1952                                 max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
1953                                 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
1954                                 max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
1955                         );
1956                 if (r_glsl_permutation->loc_OffsetMapping_LodDistance >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer * r_refdef.view.quality);
1957                 if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, t->offsetbias);
1958                 if (r_glsl_permutation->loc_ScreenToDepth >= 0) qglUniform2f(r_glsl_permutation->loc_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
1959                 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
1960                 if (r_glsl_permutation->loc_BounceGridMatrix >= 0) {Matrix4x4_Concat(&tempmatrix, &r_shadow_bouncegrid_state.matrix, &rsurface.matrix);Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BounceGridMatrix, 1, false, m16f);}
1961                 if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
1962
1963                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First            , r_texture_white                                     );
1964                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second           , r_texture_white                                     );
1965                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps       , r_texture_gammaramps                                );
1966                 if (r_glsl_permutation->tex_Texture_Normal          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal           , t->nmaptexture                       );
1967                 if (r_glsl_permutation->tex_Texture_Color           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color            , t->basetexture                       );
1968                 if (r_glsl_permutation->tex_Texture_Gloss           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss            , t->glosstexture                      );
1969                 if (r_glsl_permutation->tex_Texture_Glow            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow             , t->glowtexture                       );
1970                 if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal  , t->backgroundnmaptexture             );
1971                 if (r_glsl_permutation->tex_Texture_SecondaryColor  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor   , t->backgroundbasetexture             );
1972                 if (r_glsl_permutation->tex_Texture_SecondaryGloss  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss   , t->backgroundglosstexture            );
1973                 if (r_glsl_permutation->tex_Texture_SecondaryGlow   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow    , t->backgroundglowtexture             );
1974                 if (r_glsl_permutation->tex_Texture_Pants           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants            , t->pantstexture                      );
1975                 if (r_glsl_permutation->tex_Texture_Shirt           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt            , t->shirttexture                      );
1976                 if (r_glsl_permutation->tex_Texture_ReflectMask     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask      , t->reflectmasktexture                );
1977                 if (r_glsl_permutation->tex_Texture_ReflectCube     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube      , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
1978                 if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture                          );
1979                 if (r_glsl_permutation->tex_Texture_FogMask         >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask          , r_texture_fogattenuation                            );
1980                 if (r_glsl_permutation->tex_Texture_Lightmap        >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap         , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
1981                 if (r_glsl_permutation->tex_Texture_Deluxemap       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Deluxemap        , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap);
1982                 if (r_glsl_permutation->tex_Texture_Attenuation     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation      , r_shadow_attenuationgradienttexture                 );
1983                 if (rsurfacepass == RSURFPASS_BACKGROUND)
1984                 {
1985                         if (r_glsl_permutation->tex_Texture_Refraction  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Refraction        , waterplane->rt_refraction ? waterplane->rt_refraction->colortexture[0] : r_texture_black);
1986                         if (r_glsl_permutation->tex_Texture_First       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First             , waterplane->rt_camera ? waterplane->rt_camera->colortexture[0] : r_texture_black);
1987                         if (r_glsl_permutation->tex_Texture_Reflection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection        , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
1988                 }
1989                 else
1990                 {
1991                         if (r_glsl_permutation->tex_Texture_Reflection >= 0 && waterplane) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection        , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
1992                 }
1993                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap   , r_shadow_prepassgeometrynormalmaptexture            );
1994                 if (r_glsl_permutation->tex_Texture_ScreenDiffuse   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse     , r_shadow_prepasslightingdiffusetexture              );
1995                 if (r_glsl_permutation->tex_Texture_ScreenSpecular  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular    , r_shadow_prepasslightingspeculartexture             );
1996                 if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
1997                 {
1998                         if (r_glsl_permutation->tex_Texture_ShadowMap2D     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture                           );
1999                         if (rsurface.rtlight)
2000                         {
2001                                 if (r_glsl_permutation->tex_Texture_Cube            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube              , rsurface.rtlight->currentcubemap                    );
2002                                 if (r_glsl_permutation->tex_Texture_CubeProjection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection    , r_shadow_shadowmapvsdcttexture                      );
2003                         }
2004                 }
2005                 if (r_glsl_permutation->tex_Texture_BounceGrid  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
2006                 CHECKGLERROR
2007                 break;
2008         }
2009 }
2010
2011 void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
2012 {
2013         // select a permutation of the lighting shader appropriate to this
2014         // combination of texture, entity, light source, and fogging, only use the
2015         // minimum features necessary to avoid wasting rendering time in the
2016         // fragment shader on features that are not being used
2017         dpuint64 permutation = 0;
2018         unsigned int mode = 0;
2019         const float *lightcolorbase = rtlight->currentcolor;
2020         float ambientscale = rtlight->ambientscale;
2021         float diffusescale = rtlight->diffusescale;
2022         float specularscale = rtlight->specularscale;
2023         // this is the location of the light in view space
2024         vec3_t viewlightorigin;
2025         // this transforms from view space (camera) to light space (cubemap)
2026         matrix4x4_t viewtolight;
2027         matrix4x4_t lighttoview;
2028         float viewtolight16f[16];
2029         // light source
2030         mode = SHADERMODE_DEFERREDLIGHTSOURCE;
2031         if (rtlight->currentcubemap != r_texture_whitecube)
2032                 permutation |= SHADERPERMUTATION_CUBEFILTER;
2033         if (diffusescale > 0)
2034                 permutation |= SHADERPERMUTATION_DIFFUSE;
2035         if (specularscale > 0 && r_shadow_gloss.integer > 0)
2036                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2037         if (r_shadow_usingshadowmap2d)
2038         {
2039                 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
2040                 if (r_shadow_shadowmapvsdct)
2041                         permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
2042
2043                 if (r_shadow_shadowmap2ddepthbuffer)
2044                         permutation |= SHADERPERMUTATION_DEPTHRGB;
2045         }
2046         if (vid.allowalphatocoverage)
2047                 GL_AlphaToCoverage(false);
2048         Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
2049         Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
2050         Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
2051         Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
2052         switch(vid.renderpath)
2053         {
2054         case RENDERPATH_GL32:
2055         case RENDERPATH_GLES2:
2056                 R_SetupShader_SetPermutationGLSL(mode, permutation);
2057                 if (r_glsl_permutation->loc_LightPosition             >= 0) qglUniform3f(       r_glsl_permutation->loc_LightPosition            , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
2058                 if (r_glsl_permutation->loc_ViewToLight               >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight              , 1, false, viewtolight16f);
2059                 if (r_glsl_permutation->loc_DeferredColor_Ambient     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Ambient    , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
2060                 if (r_glsl_permutation->loc_DeferredColor_Diffuse     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
2061                 if (r_glsl_permutation->loc_DeferredColor_Specular    >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Specular   , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
2062                 if (r_glsl_permutation->loc_ShadowMap_TextureScale    >= 0) qglUniform4f(       r_glsl_permutation->loc_ShadowMap_TextureScale   , r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
2063                 if (r_glsl_permutation->loc_ShadowMap_Parameters      >= 0) qglUniform4f(       r_glsl_permutation->loc_ShadowMap_Parameters     , r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
2064                 if (r_glsl_permutation->loc_SpecularPower             >= 0) qglUniform1f(       r_glsl_permutation->loc_SpecularPower            , (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
2065                 if (r_glsl_permutation->loc_ScreenToDepth             >= 0) qglUniform2f(       r_glsl_permutation->loc_ScreenToDepth            , r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
2066                 if (r_glsl_permutation->loc_PixelToScreenTexCoord     >= 0) qglUniform2f(       r_glsl_permutation->loc_PixelToScreenTexCoord    , 1.0f/vid.width, 1.0f/vid.height);
2067
2068                 if (r_glsl_permutation->tex_Texture_Attenuation       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation        , r_shadow_attenuationgradienttexture                 );
2069                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap    , r_shadow_prepassgeometrynormalmaptexture            );
2070                 if (r_glsl_permutation->tex_Texture_Cube              >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube               , rsurface.rtlight->currentcubemap                    );
2071                 if (r_glsl_permutation->tex_Texture_ShadowMap2D       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D        , r_shadow_shadowmap2ddepthtexture                    );
2072                 if (r_glsl_permutation->tex_Texture_CubeProjection    >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection     , r_shadow_shadowmapvsdcttexture                      );
2073                 break;
2074         }
2075 }
2076
2077 #define SKINFRAME_HASH 1024
2078
2079 typedef struct
2080 {
2081         unsigned int loadsequence; // incremented each level change
2082         memexpandablearray_t array;
2083         skinframe_t *hash[SKINFRAME_HASH];
2084 }
2085 r_skinframe_t;
2086 r_skinframe_t r_skinframe;
2087
2088 void R_SkinFrame_PrepareForPurge(void)
2089 {
2090         r_skinframe.loadsequence++;
2091         // wrap it without hitting zero
2092         if (r_skinframe.loadsequence >= 200)
2093                 r_skinframe.loadsequence = 1;
2094 }
2095
2096 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
2097 {
2098         if (!skinframe)
2099                 return;
2100         // mark the skinframe as used for the purging code
2101         skinframe->loadsequence = r_skinframe.loadsequence;
2102 }
2103
2104 void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
2105 {
2106         if (s == NULL)
2107                 return;
2108         if (s->merged == s->base)
2109                 s->merged = NULL;
2110         R_PurgeTexture(s->stain); s->stain = NULL;
2111         R_PurgeTexture(s->merged); s->merged = NULL;
2112         R_PurgeTexture(s->base); s->base = NULL;
2113         R_PurgeTexture(s->pants); s->pants = NULL;
2114         R_PurgeTexture(s->shirt); s->shirt = NULL;
2115         R_PurgeTexture(s->nmap); s->nmap = NULL;
2116         R_PurgeTexture(s->gloss); s->gloss = NULL;
2117         R_PurgeTexture(s->glow); s->glow = NULL;
2118         R_PurgeTexture(s->fog); s->fog = NULL;
2119         R_PurgeTexture(s->reflect); s->reflect = NULL;
2120         s->loadsequence = 0;
2121 }
2122
2123 void R_SkinFrame_Purge(void)
2124 {
2125         int i;
2126         skinframe_t *s;
2127         for (i = 0;i < SKINFRAME_HASH;i++)
2128         {
2129                 for (s = r_skinframe.hash[i];s;s = s->next)
2130                 {
2131                         if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
2132                                 R_SkinFrame_PurgeSkinFrame(s);
2133                 }
2134         }
2135 }
2136
2137 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
2138         skinframe_t *item;
2139         char basename[MAX_QPATH];
2140
2141         Image_StripImageExtension(name, basename, sizeof(basename));
2142
2143         if( last == NULL ) {
2144                 int hashindex;
2145                 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2146                 item = r_skinframe.hash[hashindex];
2147         } else {
2148                 item = last->next;
2149         }
2150
2151         // linearly search through the hash bucket
2152         for( ; item ; item = item->next ) {
2153                 if( !strcmp( item->basename, basename ) ) {
2154                         return item;
2155                 }
2156         }
2157         return NULL;
2158 }
2159
2160 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add)
2161 {
2162         skinframe_t *item;
2163         int compareflags = textureflags & TEXF_IMPORTANTBITS;
2164         int hashindex;
2165         char basename[MAX_QPATH];
2166
2167         Image_StripImageExtension(name, basename, sizeof(basename));
2168
2169         hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2170         for (item = r_skinframe.hash[hashindex];item;item = item->next)
2171                 if (!strcmp(item->basename, basename) &&
2172                         item->textureflags == compareflags &&
2173                         item->comparewidth == comparewidth &&
2174                         item->compareheight == compareheight &&
2175                         item->comparecrc == comparecrc)
2176                         break;
2177
2178         if (!item)
2179         {
2180                 if (!add)
2181                         return NULL;
2182                 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
2183                 memset(item, 0, sizeof(*item));
2184                 strlcpy(item->basename, basename, sizeof(item->basename));
2185                 item->textureflags = compareflags;
2186                 item->comparewidth = comparewidth;
2187                 item->compareheight = compareheight;
2188                 item->comparecrc = comparecrc;
2189                 item->next = r_skinframe.hash[hashindex];
2190                 r_skinframe.hash[hashindex] = item;
2191         }
2192         else if (textureflags & TEXF_FORCE_RELOAD)
2193                 R_SkinFrame_PurgeSkinFrame(item);
2194
2195         R_SkinFrame_MarkUsed(item);
2196         return item;
2197 }
2198
2199 #define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
2200         { \
2201                 unsigned long long avgcolor[5], wsum; \
2202                 int pix, comp, w; \
2203                 avgcolor[0] = 0; \
2204                 avgcolor[1] = 0; \
2205                 avgcolor[2] = 0; \
2206                 avgcolor[3] = 0; \
2207                 avgcolor[4] = 0; \
2208                 wsum = 0; \
2209                 for(pix = 0; pix < cnt; ++pix) \
2210                 { \
2211                         w = 0; \
2212                         for(comp = 0; comp < 3; ++comp) \
2213                                 w += getpixel; \
2214                         if(w) /* ignore perfectly black pixels because that is better for model skins */ \
2215                         { \
2216                                 ++wsum; \
2217                                 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2218                                 w = getpixel; \
2219                                 for(comp = 0; comp < 3; ++comp) \
2220                                         avgcolor[comp] += getpixel * w; \
2221                                 avgcolor[3] += w; \
2222                         } \
2223                         /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2224                         avgcolor[4] += getpixel; \
2225                 } \
2226                 if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
2227                         avgcolor[3] = 1; \
2228                 skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
2229                 skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
2230                 skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
2231                 skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
2232         }
2233
2234 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2235 {
2236         skinframe_t *skinframe;
2237
2238         if (cls.state == ca_dedicated)
2239                 return NULL;
2240
2241         // return an existing skinframe if already loaded
2242         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
2243         if (skinframe && skinframe->base)
2244                 return skinframe;
2245
2246         // if the skinframe doesn't exist this will create it
2247         return R_SkinFrame_LoadExternal_SkinFrame(skinframe, name, textureflags, complain, fallbacknotexture);
2248 }
2249
2250 extern cvar_t gl_picmip;
2251 skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2252 {
2253         int j;
2254         unsigned char *pixels;
2255         unsigned char *bumppixels;
2256         unsigned char *basepixels = NULL;
2257         int basepixels_width = 0;
2258         int basepixels_height = 0;
2259         rtexture_t *ddsbase = NULL;
2260         qboolean ddshasalpha = false;
2261         float ddsavgcolor[4];
2262         char basename[MAX_QPATH];
2263         int miplevel = R_PicmipForFlags(textureflags);
2264         int savemiplevel = miplevel;
2265         int mymiplevel;
2266         char vabuf[1024];
2267
2268         if (cls.state == ca_dedicated)
2269                 return NULL;
2270
2271         Image_StripImageExtension(name, basename, sizeof(basename));
2272
2273         // check for DDS texture file first
2274         if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2275         {
2276                 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2277                 if (basepixels == NULL && fallbacknotexture)
2278                         basepixels = Image_GenerateNoTexture();
2279                 if (basepixels == NULL)
2280                         return NULL;
2281         }
2282
2283         // FIXME handle miplevel
2284
2285         if (developer_loading.integer)
2286                 Con_Printf("loading skin \"%s\"\n", name);
2287
2288         // we've got some pixels to store, so really allocate this new texture now
2289         if (!skinframe)
2290                 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2291         textureflags &= ~TEXF_FORCE_RELOAD;
2292         skinframe->stain = NULL;
2293         skinframe->merged = NULL;
2294         skinframe->base = NULL;
2295         skinframe->pants = NULL;
2296         skinframe->shirt = NULL;
2297         skinframe->nmap = NULL;
2298         skinframe->gloss = NULL;
2299         skinframe->glow = NULL;
2300         skinframe->fog = NULL;
2301         skinframe->reflect = NULL;
2302         skinframe->hasalpha = false;
2303         // we could store the q2animname here too
2304
2305         if (ddsbase)
2306         {
2307                 skinframe->base = ddsbase;
2308                 skinframe->hasalpha = ddshasalpha;
2309                 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2310                 if (r_loadfog && skinframe->hasalpha)
2311                         skinframe->fog = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), false, textureflags | TEXF_ALPHA, NULL, NULL, miplevel, true);
2312                 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2313         }
2314         else
2315         {
2316                 basepixels_width = image_width;
2317                 basepixels_height = image_height;
2318                 skinframe->base = R_LoadTexture2D (r_main_texturepool, skinframe->basename, basepixels_width, basepixels_height, basepixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL);
2319                 if (textureflags & TEXF_ALPHA)
2320                 {
2321                         for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2322                         {
2323                                 if (basepixels[j] < 255)
2324                                 {
2325                                         skinframe->hasalpha = true;
2326                                         break;
2327                                 }
2328                         }
2329                         if (r_loadfog && skinframe->hasalpha)
2330                         {
2331                                 // has transparent pixels
2332                                 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2333                                 for (j = 0;j < image_width * image_height * 4;j += 4)
2334                                 {
2335                                         pixels[j+0] = 255;
2336                                         pixels[j+1] = 255;
2337                                         pixels[j+2] = 255;
2338                                         pixels[j+3] = basepixels[j+3];
2339                                 }
2340                                 skinframe->fog = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_mask", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL);
2341                                 Mem_Free(pixels);
2342                         }
2343                 }
2344                 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2345 #ifndef USE_GLES2
2346                 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2347                 if (r_savedds && skinframe->base)
2348                         R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2349                 if (r_savedds && skinframe->fog)
2350                         R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2351 #endif
2352         }
2353
2354         if (r_loaddds)
2355         {
2356                 mymiplevel = savemiplevel;
2357                 if (r_loadnormalmap)
2358                         skinframe->nmap = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), false, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), NULL, NULL, mymiplevel, true);
2359                 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2360                 if (r_loadgloss)
2361                         skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2362                 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2363                 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2364                 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2365         }
2366
2367         // _norm is the name used by tenebrae and has been adopted as standard
2368         if (r_loadnormalmap && skinframe->nmap == NULL)
2369         {
2370                 mymiplevel = savemiplevel;
2371                 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2372                 {
2373                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2374                         Mem_Free(pixels);
2375                         pixels = NULL;
2376                 }
2377                 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2378                 {
2379                         pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2380                         Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2381                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2382                         Mem_Free(pixels);
2383                         Mem_Free(bumppixels);
2384                 }
2385                 else if (r_shadow_bumpscale_basetexture.value > 0)
2386                 {
2387                         pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2388                         Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2389                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), basepixels_width, basepixels_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2390                         Mem_Free(pixels);
2391                 }
2392 #ifndef USE_GLES2
2393                 if (r_savedds && skinframe->nmap)
2394                         R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2395 #endif
2396         }
2397
2398         // _luma is supported only for tenebrae compatibility
2399         // _glow is the preferred name
2400         mymiplevel = savemiplevel;
2401         if (skinframe->glow == NULL && ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_glow",  skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_luma", skinframe->basename), false, false, false, &mymiplevel))))
2402         {
2403                 skinframe->glow = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_glow.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2404 #ifndef USE_GLES2
2405                 if (r_savedds && skinframe->glow)
2406                         R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2407 #endif
2408                 Mem_Free(pixels);pixels = NULL;
2409         }
2410
2411         mymiplevel = savemiplevel;
2412         if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2413         {
2414                 skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (gl_texturecompression_gloss.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2415 #ifndef USE_GLES2
2416                 if (r_savedds && skinframe->gloss)
2417                         R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2418 #endif
2419                 Mem_Free(pixels);
2420                 pixels = NULL;
2421         }
2422
2423         mymiplevel = savemiplevel;
2424         if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2425         {
2426                 skinframe->pants = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2427 #ifndef USE_GLES2
2428                 if (r_savedds && skinframe->pants)
2429                         R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2430 #endif
2431                 Mem_Free(pixels);
2432                 pixels = NULL;
2433         }
2434
2435         mymiplevel = savemiplevel;
2436         if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2437         {
2438                 skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2439 #ifndef USE_GLES2
2440                 if (r_savedds && skinframe->shirt)
2441                         R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2442 #endif
2443                 Mem_Free(pixels);
2444                 pixels = NULL;
2445         }
2446
2447         mymiplevel = savemiplevel;
2448         if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2449         {
2450                 skinframe->reflect = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_reflectmask.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2451 #ifndef USE_GLES2
2452                 if (r_savedds && skinframe->reflect)
2453                         R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2454 #endif
2455                 Mem_Free(pixels);
2456                 pixels = NULL;
2457         }
2458
2459         if (basepixels)
2460                 Mem_Free(basepixels);
2461
2462         return skinframe;
2463 }
2464
2465 skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, int comparewidth, int compareheight, int comparecrc, qboolean sRGB)
2466 {
2467         int i;
2468         skinframe_t *skinframe;
2469         char vabuf[1024];
2470
2471         if (cls.state == ca_dedicated)
2472                 return NULL;
2473
2474         // if already loaded just return it, otherwise make a new skinframe
2475         skinframe = R_SkinFrame_Find(name, textureflags, comparewidth, compareheight, comparecrc, true);
2476         if (skinframe->base)
2477                 return skinframe;
2478         textureflags &= ~TEXF_FORCE_RELOAD;
2479
2480         skinframe->stain = NULL;
2481         skinframe->merged = NULL;
2482         skinframe->base = NULL;
2483         skinframe->pants = NULL;
2484         skinframe->shirt = NULL;
2485         skinframe->nmap = NULL;
2486         skinframe->gloss = NULL;
2487         skinframe->glow = NULL;
2488         skinframe->fog = NULL;
2489         skinframe->reflect = NULL;
2490         skinframe->hasalpha = false;
2491
2492         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2493         if (!skindata)
2494                 return NULL;
2495
2496         if (developer_loading.integer)
2497                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2498
2499         if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2500         {
2501                 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2502                 unsigned char *b = a + width * height * 4;
2503                 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2504                 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, b, TEXTYPE_BGRA, (textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
2505                 Mem_Free(a);
2506         }
2507         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2508         if (textureflags & TEXF_ALPHA)
2509         {
2510                 for (i = 3;i < width * height * 4;i += 4)
2511                 {
2512                         if (skindata[i] < 255)
2513                         {
2514                                 skinframe->hasalpha = true;
2515                                 break;
2516                         }
2517                 }
2518                 if (r_loadfog && skinframe->hasalpha)
2519                 {
2520                         unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2521                         memcpy(fogpixels, skindata, width * height * 4);
2522                         for (i = 0;i < width * height * 4;i += 4)
2523                                 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2524                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2525                         Mem_Free(fogpixels);
2526                 }
2527         }
2528
2529         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2530         //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2531
2532         return skinframe;
2533 }
2534
2535 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2536 {
2537         int i;
2538         int featuresmask;
2539         skinframe_t *skinframe;
2540
2541         if (cls.state == ca_dedicated)
2542                 return NULL;
2543
2544         // if already loaded just return it, otherwise make a new skinframe
2545         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2546         if (skinframe->base)
2547                 return skinframe;
2548         //textureflags &= ~TEXF_FORCE_RELOAD;
2549
2550         skinframe->stain = NULL;
2551         skinframe->merged = NULL;
2552         skinframe->base = NULL;
2553         skinframe->pants = NULL;
2554         skinframe->shirt = NULL;
2555         skinframe->nmap = NULL;
2556         skinframe->gloss = NULL;
2557         skinframe->glow = NULL;
2558         skinframe->fog = NULL;
2559         skinframe->reflect = NULL;
2560         skinframe->hasalpha = false;
2561
2562         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2563         if (!skindata)
2564                 return NULL;
2565
2566         if (developer_loading.integer)
2567                 Con_Printf("loading quake skin \"%s\"\n", name);
2568
2569         // we actually don't upload anything until the first use, because mdl skins frequently go unused, and are almost never used in both modes (colormapped and non-colormapped)
2570         skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2571         memcpy(skinframe->qpixels, skindata, width*height);
2572         skinframe->qwidth = width;
2573         skinframe->qheight = height;
2574
2575         featuresmask = 0;
2576         for (i = 0;i < width * height;i++)
2577                 featuresmask |= palette_featureflags[skindata[i]];
2578
2579         skinframe->hasalpha = false;
2580         // fence textures
2581         if (name[0] == '{')
2582                 skinframe->hasalpha = true;
2583         skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2584         skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2585         skinframe->qgeneratemerged = true;
2586         skinframe->qgeneratebase = skinframe->qhascolormapping;
2587         skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2588
2589         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2590         //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2591
2592         return skinframe;
2593 }
2594
2595 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboolean colormapped)
2596 {
2597         int width;
2598         int height;
2599         unsigned char *skindata;
2600         char vabuf[1024];
2601
2602         if (!skinframe->qpixels)
2603                 return;
2604
2605         if (!skinframe->qhascolormapping)
2606                 colormapped = false;
2607
2608         if (colormapped)
2609         {
2610                 if (!skinframe->qgeneratebase)
2611                         return;
2612         }
2613         else
2614         {
2615                 if (!skinframe->qgeneratemerged)
2616                         return;
2617         }
2618
2619         width = skinframe->qwidth;
2620         height = skinframe->qheight;
2621         skindata = skinframe->qpixels;
2622
2623         if (skinframe->qgeneratenmap)
2624         {
2625                 unsigned char *a, *b;
2626                 skinframe->qgeneratenmap = false;
2627                 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2628                 b = a + width * height * 4;
2629                 // use either a custom palette or the quake palette
2630                 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2631                 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2632                 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, b, TEXTYPE_BGRA, (skinframe->textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
2633                 Mem_Free(a);
2634         }
2635
2636         if (skinframe->qgenerateglow)
2637         {
2638                 skinframe->qgenerateglow = false;
2639                 if (skinframe->hasalpha) // fence textures
2640                         skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags | TEXF_ALPHA, -1, palette_bgra_onlyfullbrights_transparent); // glow
2641                 else
2642                         skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_onlyfullbrights); // glow
2643         }
2644
2645         if (colormapped)
2646         {
2647                 skinframe->qgeneratebase = false;
2648                 skinframe->base  = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nospecial", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nocolormapnofullbrights : palette_bgra_nocolormap);
2649                 skinframe->pants = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_pantsaswhite);
2650                 skinframe->shirt = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_shirtaswhite);
2651         }
2652         else
2653         {
2654                 skinframe->qgeneratemerged = false;
2655                 if (skinframe->hasalpha) // fence textures
2656                         skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags | TEXF_ALPHA, -1, skinframe->glow ? palette_bgra_nofullbrights_transparent : palette_bgra_transparent);
2657                 else
2658                         skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nofullbrights : palette_bgra_complete);
2659         }
2660
2661         if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2662         {
2663                 Mem_Free(skinframe->qpixels);
2664                 skinframe->qpixels = NULL;
2665         }
2666 }
2667
2668 skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, const unsigned char *skindata, int width, int height, const unsigned int *palette, const unsigned int *alphapalette)
2669 {
2670         int i;
2671         skinframe_t *skinframe;
2672         char vabuf[1024];
2673
2674         if (cls.state == ca_dedicated)
2675                 return NULL;
2676
2677         // if already loaded just return it, otherwise make a new skinframe
2678         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2679         if (skinframe->base)
2680                 return skinframe;
2681         textureflags &= ~TEXF_FORCE_RELOAD;
2682
2683         skinframe->stain = NULL;
2684         skinframe->merged = NULL;
2685         skinframe->base = NULL;
2686         skinframe->pants = NULL;
2687         skinframe->shirt = NULL;
2688         skinframe->nmap = NULL;
2689         skinframe->gloss = NULL;
2690         skinframe->glow = NULL;
2691         skinframe->fog = NULL;
2692         skinframe->reflect = NULL;
2693         skinframe->hasalpha = false;
2694
2695         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2696         if (!skindata)
2697                 return NULL;
2698
2699         if (developer_loading.integer)
2700                 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2701
2702         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2703         if ((textureflags & TEXF_ALPHA) && alphapalette)
2704         {
2705                 for (i = 0;i < width * height;i++)
2706                 {
2707                         if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2708                         {
2709                                 skinframe->hasalpha = true;
2710                                 break;
2711                         }
2712                 }
2713                 if (r_loadfog && skinframe->hasalpha)
2714                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2715         }
2716
2717         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2718         //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2719
2720         return skinframe;
2721 }
2722
2723 skinframe_t *R_SkinFrame_LoadMissing(void)
2724 {
2725         skinframe_t *skinframe;
2726
2727         if (cls.state == ca_dedicated)
2728                 return NULL;
2729
2730         skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2731         skinframe->stain = NULL;
2732         skinframe->merged = NULL;
2733         skinframe->base = NULL;
2734         skinframe->pants = NULL;
2735         skinframe->shirt = NULL;
2736         skinframe->nmap = NULL;
2737         skinframe->gloss = NULL;
2738         skinframe->glow = NULL;
2739         skinframe->fog = NULL;
2740         skinframe->reflect = NULL;
2741         skinframe->hasalpha = false;
2742
2743         skinframe->avgcolor[0] = rand() / RAND_MAX;
2744         skinframe->avgcolor[1] = rand() / RAND_MAX;
2745         skinframe->avgcolor[2] = rand() / RAND_MAX;
2746         skinframe->avgcolor[3] = 1;
2747
2748         return skinframe;
2749 }
2750
2751 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2752 {
2753         int x, y;
2754         static unsigned char pix[16][16][4];
2755
2756         if (cls.state == ca_dedicated)
2757                 return NULL;
2758
2759         // this makes a light grey/dark grey checkerboard texture
2760         if (!pix[0][0][3])
2761         {
2762                 for (y = 0; y < 16; y++)
2763                 {
2764                         for (x = 0; x < 16; x++)
2765                         {
2766                                 if ((y < 8) ^ (x < 8))
2767                                 {
2768                                         pix[y][x][0] = 128;
2769                                         pix[y][x][1] = 128;
2770                                         pix[y][x][2] = 128;
2771                                         pix[y][x][3] = 255;
2772                                 }
2773                                 else
2774                                 {
2775                                         pix[y][x][0] = 64;
2776                                         pix[y][x][1] = 64;
2777                                         pix[y][x][2] = 64;
2778                                         pix[y][x][3] = 255;
2779                                 }
2780                         }
2781                 }
2782         }
2783
2784         return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, pix[0][0], 16, 16, 0, 0, 0, false);
2785 }
2786
2787 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qboolean sRGB)
2788 {
2789         skinframe_t *skinframe;
2790         if (cls.state == ca_dedicated)
2791                 return NULL;
2792         // if already loaded just return it, otherwise make a new skinframe
2793         skinframe = R_SkinFrame_Find(name, textureflags, width, height, 0, true);
2794         if (skinframe->base)
2795                 return skinframe;
2796         textureflags &= ~TEXF_FORCE_RELOAD;
2797         skinframe->stain = NULL;
2798         skinframe->merged = NULL;
2799         skinframe->base = NULL;
2800         skinframe->pants = NULL;
2801         skinframe->shirt = NULL;
2802         skinframe->nmap = NULL;
2803         skinframe->gloss = NULL;
2804         skinframe->glow = NULL;
2805         skinframe->fog = NULL;
2806         skinframe->reflect = NULL;
2807         skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2808         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2809         if (!tex)
2810                 return NULL;
2811         if (developer_loading.integer)
2812                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2813         skinframe->base = skinframe->merged = tex;
2814         Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2815         return skinframe;
2816 }
2817
2818 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2819 typedef struct suffixinfo_s
2820 {
2821         const char *suffix;
2822         qboolean flipx, flipy, flipdiagonal;
2823 }
2824 suffixinfo_t;
2825 static suffixinfo_t suffix[3][6] =
2826 {
2827         {
2828                 {"px",   false, false, false},
2829                 {"nx",   false, false, false},
2830                 {"py",   false, false, false},
2831                 {"ny",   false, false, false},
2832                 {"pz",   false, false, false},
2833                 {"nz",   false, false, false}
2834         },
2835         {
2836                 {"posx", false, false, false},
2837                 {"negx", false, false, false},
2838                 {"posy", false, false, false},
2839                 {"negy", false, false, false},
2840                 {"posz", false, false, false},
2841                 {"negz", false, false, false}
2842         },
2843         {
2844                 {"rt",    true, false,  true},
2845                 {"lf",   false,  true,  true},
2846                 {"ft",    true,  true, false},
2847                 {"bk",   false, false, false},
2848                 {"up",    true, false,  true},
2849                 {"dn",    true, false,  true}
2850         }
2851 };
2852
2853 static int componentorder[4] = {0, 1, 2, 3};
2854
2855 static rtexture_t *R_LoadCubemap(const char *basename)
2856 {
2857         int i, j, cubemapsize;
2858         unsigned char *cubemappixels, *image_buffer;
2859         rtexture_t *cubemaptexture;
2860         char name[256];
2861         // must start 0 so the first loadimagepixels has no requested width/height
2862         cubemapsize = 0;
2863         cubemappixels = NULL;
2864         cubemaptexture = NULL;
2865         // keep trying different suffix groups (posx, px, rt) until one loads
2866         for (j = 0;j < 3 && !cubemappixels;j++)
2867         {
2868                 // load the 6 images in the suffix group
2869                 for (i = 0;i < 6;i++)
2870                 {
2871                         // generate an image name based on the base and and suffix
2872                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2873                         // load it
2874                         if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
2875                         {
2876                                 // an image loaded, make sure width and height are equal
2877                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
2878                                 {
2879                                         // if this is the first image to load successfully, allocate the cubemap memory
2880                                         if (!cubemappixels && image_width >= 1)
2881                                         {
2882                                                 cubemapsize = image_width;
2883                                                 // note this clears to black, so unavailable sides are black
2884                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2885                                         }
2886                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2887                                         if (cubemappixels)
2888                                                 Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_buffer, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder);
2889                                 }
2890                                 else
2891                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2892                                 // free the image
2893                                 Mem_Free(image_buffer);
2894                         }
2895                 }
2896         }
2897         // if a cubemap loaded, upload it
2898         if (cubemappixels)
2899         {
2900                 if (developer_loading.integer)
2901                         Con_Printf("loading cubemap \"%s\"\n", basename);
2902
2903                 cubemaptexture = R_LoadTextureCubeMap(r_main_texturepool, basename, cubemapsize, cubemappixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, (gl_texturecompression_lightcubemaps.integer && gl_texturecompression.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
2904                 Mem_Free(cubemappixels);
2905         }
2906         else
2907         {
2908                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
2909                 if (developer_loading.integer)
2910                 {
2911                         Con_Printf("(tried tried images ");
2912                         for (j = 0;j < 3;j++)
2913                                 for (i = 0;i < 6;i++)
2914                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2915                         Con_Print(" and was unable to find any of them).\n");
2916                 }
2917         }
2918         return cubemaptexture;
2919 }
2920
2921 rtexture_t *R_GetCubemap(const char *basename)
2922 {
2923         int i;
2924         for (i = 0;i < r_texture_numcubemaps;i++)
2925                 if (r_texture_cubemaps[i] != NULL)
2926                         if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
2927                                 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
2928         if (i >= MAX_CUBEMAPS || !r_main_mempool)
2929                 return r_texture_whitecube;
2930         r_texture_numcubemaps++;
2931         r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
2932         strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
2933         r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
2934         return r_texture_cubemaps[i]->texture;
2935 }
2936
2937 static void R_Main_FreeViewCache(void)
2938 {
2939         if (r_refdef.viewcache.entityvisible)
2940                 Mem_Free(r_refdef.viewcache.entityvisible);
2941         if (r_refdef.viewcache.world_pvsbits)
2942                 Mem_Free(r_refdef.viewcache.world_pvsbits);
2943         if (r_refdef.viewcache.world_leafvisible)
2944                 Mem_Free(r_refdef.viewcache.world_leafvisible);
2945         if (r_refdef.viewcache.world_surfacevisible)
2946                 Mem_Free(r_refdef.viewcache.world_surfacevisible);
2947         memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
2948 }
2949
2950 static void R_Main_ResizeViewCache(void)
2951 {
2952         int numentities = r_refdef.scene.numentities;
2953         int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
2954         int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
2955         int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
2956         int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
2957         if (r_refdef.viewcache.maxentities < numentities)
2958         {
2959                 r_refdef.viewcache.maxentities = numentities;
2960                 if (r_refdef.viewcache.entityvisible)
2961                         Mem_Free(r_refdef.viewcache.entityvisible);
2962                 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
2963         }
2964         if (r_refdef.viewcache.world_numclusters != numclusters)
2965         {
2966                 r_refdef.viewcache.world_numclusters = numclusters;
2967                 r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
2968                 if (r_refdef.viewcache.world_pvsbits)
2969                         Mem_Free(r_refdef.viewcache.world_pvsbits);
2970                 r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
2971         }
2972         if (r_refdef.viewcache.world_numleafs != numleafs)
2973         {
2974                 r_refdef.viewcache.world_numleafs = numleafs;
2975                 if (r_refdef.viewcache.world_leafvisible)
2976                         Mem_Free(r_refdef.viewcache.world_leafvisible);
2977                 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
2978         }
2979         if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
2980         {
2981                 r_refdef.viewcache.world_numsurfaces = numsurfaces;
2982                 if (r_refdef.viewcache.world_surfacevisible)
2983                         Mem_Free(r_refdef.viewcache.world_surfacevisible);
2984                 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
2985         }
2986 }
2987
2988 extern rtexture_t *loadingscreentexture;
2989 static void gl_main_start(void)
2990 {
2991         loadingscreentexture = NULL;
2992         r_texture_blanknormalmap = NULL;
2993         r_texture_white = NULL;
2994         r_texture_grey128 = NULL;
2995         r_texture_black = NULL;
2996         r_texture_whitecube = NULL;
2997         r_texture_normalizationcube = NULL;
2998         r_texture_fogattenuation = NULL;
2999         r_texture_fogheighttexture = NULL;
3000         r_texture_gammaramps = NULL;
3001         r_texture_numcubemaps = 0;
3002         r_uniformbufferalignment = 32;
3003
3004         r_loaddds = r_texture_dds_load.integer != 0;
3005         r_savedds = vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3006
3007         switch(vid.renderpath)
3008         {
3009         case RENDERPATH_GL32:
3010         case RENDERPATH_GLES2:
3011                 Cvar_SetValueQuick(&r_textureunits, MAX_TEXTUREUNITS);
3012                 Cvar_SetValueQuick(&gl_combine, 1);
3013                 Cvar_SetValueQuick(&r_glsl, 1);
3014                 r_loadnormalmap = true;
3015                 r_loadgloss = true;
3016                 r_loadfog = false;
3017 #ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
3018                 qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
3019 #endif
3020                 break;
3021         }
3022
3023         R_AnimCache_Free();
3024         R_FrameData_Reset();
3025         R_BufferData_Reset();
3026
3027         r_numqueries = 0;
3028         r_maxqueries = 0;
3029         memset(r_queries, 0, sizeof(r_queries));
3030
3031         r_qwskincache = NULL;
3032         r_qwskincache_size = 0;
3033
3034         // due to caching of texture_t references, the collision cache must be reset
3035         Collision_Cache_Reset(true);
3036
3037         // set up r_skinframe loading system for textures
3038         memset(&r_skinframe, 0, sizeof(r_skinframe));
3039         r_skinframe.loadsequence = 1;
3040         Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
3041
3042         r_main_texturepool = R_AllocTexturePool();
3043         R_BuildBlankTextures();
3044         R_BuildNoTexture();
3045         R_BuildWhiteCube();
3046         R_BuildNormalizationCube();
3047         r_texture_fogattenuation = NULL;
3048         r_texture_fogheighttexture = NULL;
3049         r_texture_gammaramps = NULL;
3050         //r_texture_fogintensity = NULL;
3051         memset(&r_fb, 0, sizeof(r_fb));
3052         Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
3053         r_glsl_permutation = NULL;
3054         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3055         Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
3056         memset(&r_svbsp, 0, sizeof (r_svbsp));
3057
3058         memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
3059         r_texture_numcubemaps = 0;
3060
3061         r_refdef.fogmasktable_density = 0;
3062
3063 #ifdef __ANDROID__
3064         // For Steelstorm Android
3065         // FIXME CACHE the program and reload
3066         // FIXME see possible combinations for SS:BR android
3067         Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
3068         R_SetupShader_SetPermutationGLSL(0, 12);
3069         R_SetupShader_SetPermutationGLSL(0, 13);
3070         R_SetupShader_SetPermutationGLSL(0, 8388621);
3071         R_SetupShader_SetPermutationGLSL(3, 0);
3072         R_SetupShader_SetPermutationGLSL(3, 2048);
3073         R_SetupShader_SetPermutationGLSL(5, 0);
3074         R_SetupShader_SetPermutationGLSL(5, 2);
3075         R_SetupShader_SetPermutationGLSL(5, 2048);
3076         R_SetupShader_SetPermutationGLSL(5, 8388608);
3077         R_SetupShader_SetPermutationGLSL(11, 1);
3078         R_SetupShader_SetPermutationGLSL(11, 2049);
3079         R_SetupShader_SetPermutationGLSL(11, 8193);
3080         R_SetupShader_SetPermutationGLSL(11, 10241);
3081         Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
3082 #endif
3083 }
3084
3085 static void gl_main_shutdown(void)
3086 {
3087         R_RenderTarget_FreeUnused(true);
3088         Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
3089         R_AnimCache_Free();
3090         R_FrameData_Reset();
3091         R_BufferData_Reset();
3092
3093         R_Main_FreeViewCache();
3094
3095         switch(vid.renderpath)
3096         {
3097         case RENDERPATH_GL32:
3098         case RENDERPATH_GLES2:
3099 #if defined(GL_SAMPLES_PASSED) && !defined(USE_GLES2)
3100                 if (r_maxqueries)
3101                         qglDeleteQueries(r_maxqueries, r_queries);
3102 #endif
3103                 break;
3104         }
3105
3106         r_numqueries = 0;
3107         r_maxqueries = 0;
3108         memset(r_queries, 0, sizeof(r_queries));
3109
3110         r_qwskincache = NULL;
3111         r_qwskincache_size = 0;
3112
3113         // clear out the r_skinframe state
3114         Mem_ExpandableArray_FreeArray(&r_skinframe.array);
3115         memset(&r_skinframe, 0, sizeof(r_skinframe));
3116
3117         if (r_svbsp.nodes)
3118                 Mem_Free(r_svbsp.nodes);
3119         memset(&r_svbsp, 0, sizeof (r_svbsp));
3120         R_FreeTexturePool(&r_main_texturepool);
3121         loadingscreentexture = NULL;
3122         r_texture_blanknormalmap = NULL;
3123         r_texture_white = NULL;
3124         r_texture_grey128 = NULL;
3125         r_texture_black = NULL;
3126         r_texture_whitecube = NULL;
3127         r_texture_normalizationcube = NULL;
3128         r_texture_fogattenuation = NULL;
3129         r_texture_fogheighttexture = NULL;
3130         r_texture_gammaramps = NULL;
3131         r_texture_numcubemaps = 0;
3132         //r_texture_fogintensity = NULL;
3133         memset(&r_fb, 0, sizeof(r_fb));
3134         R_GLSL_Restart_f(&cmd_client);
3135
3136         r_glsl_permutation = NULL;
3137         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3138         Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
3139 }
3140
3141 static void gl_main_newmap(void)
3142 {
3143         // FIXME: move this code to client
3144         char *entities, entname[MAX_QPATH];
3145         if (r_qwskincache)
3146                 Mem_Free(r_qwskincache);
3147         r_qwskincache = NULL;
3148         r_qwskincache_size = 0;
3149         if (cl.worldmodel)
3150         {
3151                 dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension);
3152                 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
3153                 {
3154                         CL_ParseEntityLump(entities);
3155                         Mem_Free(entities);
3156                         return;
3157                 }
3158                 if (cl.worldmodel->brush.entities)
3159                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
3160         }
3161         R_Main_FreeViewCache();
3162
3163         R_FrameData_Reset();
3164         R_BufferData_Reset();
3165 }
3166
3167 void GL_Main_Init(void)
3168 {
3169         int i;
3170         r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
3171         R_InitShaderModeInfo();
3172
3173         Cmd_AddCommand(&cmd_client, "r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
3174         Cmd_AddCommand(&cmd_client, "r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
3175         // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
3176         if (gamemode == GAME_NEHAHRA)
3177         {
3178                 Cvar_RegisterVariable (&gl_fogenable);
3179                 Cvar_RegisterVariable (&gl_fogdensity);
3180                 Cvar_RegisterVariable (&gl_fogred);
3181                 Cvar_RegisterVariable (&gl_foggreen);
3182                 Cvar_RegisterVariable (&gl_fogblue);
3183                 Cvar_RegisterVariable (&gl_fogstart);
3184                 Cvar_RegisterVariable (&gl_fogend);
3185                 Cvar_RegisterVariable (&gl_skyclip);
3186         }
3187         Cvar_RegisterVariable(&r_motionblur);
3188         Cvar_RegisterVariable(&r_damageblur);
3189         Cvar_RegisterVariable(&r_motionblur_averaging);
3190         Cvar_RegisterVariable(&r_motionblur_randomize);
3191         Cvar_RegisterVariable(&r_motionblur_minblur);
3192         Cvar_RegisterVariable(&r_motionblur_maxblur);
3193         Cvar_RegisterVariable(&r_motionblur_velocityfactor);
3194         Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed);
3195         Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed);
3196         Cvar_RegisterVariable(&r_motionblur_mousefactor);
3197         Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed);
3198         Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed);
3199         Cvar_RegisterVariable(&r_depthfirst);
3200         Cvar_RegisterVariable(&r_useinfinitefarclip);
3201         Cvar_RegisterVariable(&r_farclip_base);
3202         Cvar_RegisterVariable(&r_farclip_world);
3203         Cvar_RegisterVariable(&r_nearclip);
3204         Cvar_RegisterVariable(&r_deformvertexes);
3205         Cvar_RegisterVariable(&r_transparent);
3206         Cvar_RegisterVariable(&r_transparent_alphatocoverage);
3207         Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
3208         Cvar_RegisterVariable(&r_transparent_useplanardistance);
3209         Cvar_RegisterVariable(&r_showoverdraw);
3210         Cvar_RegisterVariable(&r_showbboxes);
3211         Cvar_RegisterVariable(&r_showbboxes_client);
3212         Cvar_RegisterVariable(&r_showsurfaces);
3213         Cvar_RegisterVariable(&r_showtris);
3214         Cvar_RegisterVariable(&r_shownormals);
3215         Cvar_RegisterVariable(&r_showlighting);
3216         Cvar_RegisterVariable(&r_showcollisionbrushes);
3217         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
3218         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
3219         Cvar_RegisterVariable(&r_showdisabledepthtest);
3220         Cvar_RegisterVariable(&r_showspriteedges);
3221         Cvar_RegisterVariable(&r_showparticleedges);
3222         Cvar_RegisterVariable(&r_drawportals);
3223         Cvar_RegisterVariable(&r_drawentities);
3224         Cvar_RegisterVariable(&r_draw2d);
3225         Cvar_RegisterVariable(&r_drawworld);
3226         Cvar_RegisterVariable(&r_cullentities_trace);
3227         Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
3228         Cvar_RegisterVariable(&r_cullentities_trace_samples);
3229         Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
3230         Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
3231         Cvar_RegisterVariable(&r_cullentities_trace_expand);
3232         Cvar_RegisterVariable(&r_cullentities_trace_pad);
3233         Cvar_RegisterVariable(&r_cullentities_trace_delay);
3234         Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
3235         Cvar_RegisterVariable(&r_sortentities);
3236         Cvar_RegisterVariable(&r_drawviewmodel);
3237         Cvar_RegisterVariable(&r_drawexteriormodel);
3238         Cvar_RegisterVariable(&r_speeds);
3239         Cvar_RegisterVariable(&r_fullbrights);
3240         Cvar_RegisterVariable(&r_wateralpha);
3241         Cvar_RegisterVariable(&r_dynamic);
3242         Cvar_RegisterVariable(&r_fullbright_directed);
3243         Cvar_RegisterVariable(&r_fullbright_directed_ambient);
3244         Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
3245         Cvar_RegisterVariable(&r_fullbright_directed_pitch);
3246         Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
3247         Cvar_RegisterVariable(&r_fullbright);
3248         Cvar_RegisterVariable(&r_shadows);
3249         Cvar_RegisterVariable(&r_shadows_darken);
3250         Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
3251         Cvar_RegisterVariable(&r_shadows_castfrombmodels);
3252         Cvar_RegisterVariable(&r_shadows_throwdistance);
3253         Cvar_RegisterVariable(&r_shadows_throwdirection);
3254         Cvar_RegisterVariable(&r_shadows_focus);
3255         Cvar_RegisterVariable(&r_shadows_shadowmapscale);
3256         Cvar_RegisterVariable(&r_shadows_shadowmapbias);
3257         Cvar_RegisterVariable(&r_q1bsp_skymasking);
3258         Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
3259         Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
3260         Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
3261         Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
3262         Cvar_RegisterVariable(&r_fog_exp2);
3263         Cvar_RegisterVariable(&r_fog_clear);
3264         Cvar_RegisterVariable(&r_drawfog);
3265         Cvar_RegisterVariable(&r_transparentdepthmasking);
3266         Cvar_RegisterVariable(&r_transparent_sortmindist);
3267         Cvar_RegisterVariable(&r_transparent_sortmaxdist);
3268         Cvar_RegisterVariable(&r_transparent_sortarraysize);
3269         Cvar_RegisterVariable(&r_texture_dds_load);
3270         Cvar_RegisterVariable(&r_texture_dds_save);
3271         Cvar_RegisterVariable(&r_textureunits);
3272         Cvar_RegisterVariable(&gl_combine);
3273         Cvar_RegisterVariable(&r_usedepthtextures);
3274         Cvar_RegisterVariable(&r_viewfbo);
3275         Cvar_RegisterVariable(&r_rendertarget_debug);
3276         Cvar_RegisterVariable(&r_viewscale);
3277         Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3278         Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3279         Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3280         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3281         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3282         Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3283         Cvar_RegisterVariable(&r_glsl);
3284         Cvar_RegisterVariable(&r_glsl_deluxemapping);
3285         Cvar_RegisterVariable(&r_glsl_offsetmapping);
3286         Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3287         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3288         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3289         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3290         Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3291         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3292         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3293         Cvar_RegisterVariable(&r_glsl_postprocess);
3294         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3295         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3296         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3297         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3298         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3299         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3300         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3301         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3302         Cvar_RegisterVariable(&r_celshading);
3303         Cvar_RegisterVariable(&r_celoutlines);
3304
3305         Cvar_RegisterVariable(&r_water);
3306         Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3307         Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3308         Cvar_RegisterVariable(&r_water_clippingplanebias);
3309         Cvar_RegisterVariable(&r_water_refractdistort);
3310         Cvar_RegisterVariable(&r_water_reflectdistort);
3311         Cvar_RegisterVariable(&r_water_scissormode);
3312         Cvar_RegisterVariable(&r_water_lowquality);
3313         Cvar_RegisterVariable(&r_water_hideplayer);
3314
3315         Cvar_RegisterVariable(&r_lerpsprites);
3316         Cvar_RegisterVariable(&r_lerpmodels);
3317         Cvar_RegisterVariable(&r_lerplightstyles);
3318         Cvar_RegisterVariable(&r_waterscroll);
3319         Cvar_RegisterVariable(&r_bloom);
3320         Cvar_RegisterVariable(&r_bloom_colorscale);
3321         Cvar_RegisterVariable(&r_bloom_brighten);
3322         Cvar_RegisterVariable(&r_bloom_blur);
3323         Cvar_RegisterVariable(&r_bloom_resolution);
3324         Cvar_RegisterVariable(&r_bloom_colorexponent);
3325         Cvar_RegisterVariable(&r_bloom_colorsubtract);
3326         Cvar_RegisterVariable(&r_bloom_scenebrightness);
3327         Cvar_RegisterVariable(&r_hdr_scenebrightness);
3328         Cvar_RegisterVariable(&r_hdr_glowintensity);
3329         Cvar_RegisterVariable(&r_hdr_irisadaptation);
3330         Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3331         Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3332         Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3333         Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3334         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3335         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3336         Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3337         Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3338         Cvar_RegisterVariable(&developer_texturelogging);
3339         Cvar_RegisterVariable(&gl_lightmaps);
3340         Cvar_RegisterVariable(&r_test);
3341         Cvar_RegisterVariable(&r_batch_multidraw);
3342         Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3343         Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3344         Cvar_RegisterVariable(&r_glsl_skeletal);
3345         Cvar_RegisterVariable(&r_glsl_saturation);
3346         Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3347         Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3348         Cvar_RegisterVariable(&r_framedatasize);
3349         for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3350                 Cvar_RegisterVariable(&r_buffermegs[i]);
3351         Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3352         if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3353                 Cvar_SetValue(&cvars_all, "r_fullbrights", 0);
3354 #ifdef DP_MOBILETOUCH
3355         // GLES devices have terrible depth precision in general, so...
3356         Cvar_SetValueQuick(&r_nearclip, 4);
3357         Cvar_SetValueQuick(&r_farclip_base, 4096);
3358         Cvar_SetValueQuick(&r_farclip_world, 0);
3359         Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3360 #endif
3361         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3362 }
3363
3364 void Render_Init(void)
3365 {
3366         gl_backend_init();
3367         R_Textures_Init();
3368         GL_Main_Init();
3369         Font_Init();
3370         GL_Draw_Init();
3371         R_Shadow_Init();
3372         R_Sky_Init();
3373         GL_Surf_Init();
3374         Sbar_Init();
3375         R_Particles_Init();
3376         R_Explosion_Init();
3377         R_LightningBeams_Init();
3378         Mod_RenderInit();
3379 }
3380
3381 int R_CullBox(const vec3_t mins, const vec3_t maxs)
3382 {
3383         int i;
3384         mplane_t *p;
3385         if (r_trippy.integer)
3386                 return false;
3387         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
3388         {
3389                 p = r_refdef.view.frustum + i;
3390                 switch(p->signbits)
3391                 {
3392                 default:
3393                 case 0:
3394                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3395                                 return true;
3396                         break;
3397                 case 1:
3398                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3399                                 return true;
3400                         break;
3401                 case 2:
3402                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3403                                 return true;
3404                         break;
3405                 case 3:
3406                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3407                                 return true;
3408                         break;
3409                 case 4:
3410                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3411                                 return true;
3412                         break;
3413                 case 5:
3414                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3415                                 return true;
3416                         break;
3417                 case 6:
3418                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3419                                 return true;
3420                         break;
3421                 case 7:
3422                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3423                                 return true;
3424                         break;
3425                 }
3426         }
3427         return false;
3428 }
3429
3430 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3431 {
3432         int i;
3433         const mplane_t *p;
3434         if (r_trippy.integer)
3435                 return false;
3436         for (i = 0;i < numplanes;i++)
3437         {
3438                 p = planes + i;
3439                 switch(p->signbits)
3440                 {
3441                 default:
3442                 case 0:
3443                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3444                                 return true;
3445                         break;
3446                 case 1:
3447                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3448                                 return true;
3449                         break;
3450                 case 2:
3451                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3452                                 return true;
3453                         break;
3454                 case 3:
3455                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3456                                 return true;
3457                         break;
3458                 case 4:
3459                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3460                                 return true;
3461                         break;
3462                 case 5:
3463                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3464                                 return true;
3465                         break;
3466                 case 6:
3467                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3468                                 return true;
3469                         break;
3470                 case 7:
3471                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3472                                 return true;
3473                         break;
3474                 }
3475         }
3476         return false;
3477 }
3478
3479 //==================================================================================
3480
3481 // LadyHavoc: this stores temporary data used within the same frame
3482
3483 typedef struct r_framedata_mem_s
3484 {
3485         struct r_framedata_mem_s *purge; // older mem block to free on next frame
3486         size_t size; // how much usable space
3487         size_t current; // how much space in use
3488         size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3489         size_t wantedsize; // how much space was allocated
3490         unsigned char *data; // start of real data (16byte aligned)
3491 }
3492 r_framedata_mem_t;
3493
3494 static r_framedata_mem_t *r_framedata_mem;
3495
3496 void R_FrameData_Reset(void)
3497 {
3498         while (r_framedata_mem)
3499         {
3500                 r_framedata_mem_t *next = r_framedata_mem->purge;
3501                 Mem_Free(r_framedata_mem);
3502                 r_framedata_mem = next;
3503         }
3504 }
3505
3506 static void R_FrameData_Resize(qboolean mustgrow)
3507 {
3508         size_t wantedsize;
3509         wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3510         wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3511         if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3512         {
3513                 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3514                 newmem->wantedsize = wantedsize;
3515                 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3516                 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3517                 newmem->current = 0;
3518                 newmem->mark = 0;
3519                 newmem->purge = r_framedata_mem;
3520                 r_framedata_mem = newmem;
3521         }
3522 }
3523
3524 void R_FrameData_NewFrame(void)
3525 {
3526         R_FrameData_Resize(false);
3527         if (!r_framedata_mem)
3528                 return;
3529         // if we ran out of space on the last frame, free the old memory now
3530         while (r_framedata_mem->purge)
3531         {
3532                 // repeatedly remove the second item in the list, leaving only head
3533                 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3534                 Mem_Free(r_framedata_mem->purge);
3535                 r_framedata_mem->purge = next;
3536         }
3537         // reset the current mem pointer
3538         r_framedata_mem->current = 0;
3539         r_framedata_mem->mark = 0;
3540 }
3541
3542 void *R_FrameData_Alloc(size_t size)
3543 {
3544         void *data;
3545         float newvalue;
3546
3547         // align to 16 byte boundary - the data pointer is already aligned, so we
3548         // only need to ensure the size of every allocation is also aligned
3549         size = (size + 15) & ~15;
3550
3551         while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3552         {
3553                 // emergency - we ran out of space, allocate more memory
3554                 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3555                 newvalue = r_framedatasize.value * 2.0f;
3556                 // upper bound based on architecture - if we try to allocate more than this we could overflow, better to loop until we error out on allocation failure
3557                 if (sizeof(size_t) >= 8)
3558                         newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3559                 else
3560                         newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3561                 // this might not be a growing it, but we'll allocate another buffer every time
3562                 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3563                 R_FrameData_Resize(true);
3564         }
3565
3566         data = r_framedata_mem->data + r_framedata_mem->current;
3567         r_framedata_mem->current += size;
3568
3569         // count the usage for stats
3570         r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3571         r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3572
3573         return (void *)data;
3574 }
3575
3576 void *R_FrameData_Store(size_t size, void *data)
3577 {
3578         void *d = R_FrameData_Alloc(size);
3579         if (d && data)
3580                 memcpy(d, data, size);
3581         return d;
3582 }
3583
3584 void R_FrameData_SetMark(void)
3585 {
3586         if (!r_framedata_mem)
3587                 return;
3588         r_framedata_mem->mark = r_framedata_mem->current;
3589 }
3590
3591 void R_FrameData_ReturnToMark(void)
3592 {
3593         if (!r_framedata_mem)
3594                 return;
3595         r_framedata_mem->current = r_framedata_mem->mark;
3596 }
3597
3598 //==================================================================================
3599
3600 // avoid reusing the same buffer objects on consecutive frames
3601 #define R_BUFFERDATA_CYCLE 3
3602
3603 typedef struct r_bufferdata_buffer_s
3604 {
3605         struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3606         size_t size; // how much usable space
3607         size_t current; // how much space in use
3608         r_meshbuffer_t *buffer; // the buffer itself
3609 }
3610 r_bufferdata_buffer_t;
3611
3612 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3613 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3614
3615 /// frees all dynamic buffers
3616 void R_BufferData_Reset(void)
3617 {
3618         int cycle, type;
3619         r_bufferdata_buffer_t **p, *mem;
3620         for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3621         {
3622                 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3623                 {
3624                         // free all buffers
3625                         p = &r_bufferdata_buffer[cycle][type];
3626                         while (*p)
3627                         {
3628                                 mem = *p;
3629                                 *p = (*p)->purge;
3630                                 if (mem->buffer)
3631                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3632                                 Mem_Free(mem);
3633                         }
3634                 }
3635         }
3636 }
3637
3638 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3639 static void R_BufferData_Resize(r_bufferdata_type_t type, qboolean mustgrow, size_t minsize)
3640 {
3641         r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3642         size_t size;
3643         float newvalue = r_buffermegs[type].value;
3644
3645         // increase the cvar if we have to (but only if we already have a mem)
3646         if (mustgrow && mem)
3647                 newvalue *= 2.0f;
3648         newvalue = bound(0.25f, newvalue, 256.0f);
3649         while (newvalue * 1024*1024 < minsize)
3650                 newvalue *= 2.0f;
3651
3652         // clamp the cvar to valid range
3653         newvalue = bound(0.25f, newvalue, 256.0f);
3654         if (r_buffermegs[type].value != newvalue)
3655                 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3656
3657         // calculate size in bytes
3658         size = (size_t)(newvalue * 1024*1024);
3659         size = bound(131072, size, 256*1024*1024);
3660
3661         // allocate a new buffer if the size is different (purge old one later)
3662         // or if we were told we must grow the buffer
3663         if (!mem || mem->size != size || mustgrow)
3664         {
3665                 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3666                 mem->size = size;
3667                 mem->current = 0;
3668                 if (type == R_BUFFERDATA_VERTEX)
3669                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3670                 else if (type == R_BUFFERDATA_INDEX16)
3671                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3672                 else if (type == R_BUFFERDATA_INDEX32)
3673                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3674                 else if (type == R_BUFFERDATA_UNIFORM)
3675                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3676                 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3677                 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3678         }
3679 }
3680
3681 void R_BufferData_NewFrame(void)
3682 {
3683         int type;
3684         r_bufferdata_buffer_t **p, *mem;
3685         // cycle to the next frame's buffers
3686         r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3687         // if we ran out of space on the last time we used these buffers, free the old memory now
3688         for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3689         {
3690                 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3691                 {
3692                         R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3693                         // free all but the head buffer, this is how we recycle obsolete
3694                         // buffers after they are no longer in use
3695                         p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3696                         while (*p)
3697                         {
3698                                 mem = *p;
3699                                 *p = (*p)->purge;
3700                                 if (mem->buffer)
3701                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3702                                 Mem_Free(mem);
3703                         }
3704                         // reset the current offset
3705                         r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3706                 }
3707         }
3708 }
3709
3710 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3711 {
3712         r_bufferdata_buffer_t *mem;
3713         int offset = 0;
3714         int padsize;
3715
3716         *returnbufferoffset = 0;
3717
3718         // align size to a byte boundary appropriate for the buffer type, this
3719         // makes all allocations have aligned start offsets
3720         if (type == R_BUFFERDATA_UNIFORM)
3721                 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3722         else
3723                 padsize = (datasize + 15) & ~15;
3724
3725         // if we ran out of space in this buffer we must allocate a new one
3726         if (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size)
3727                 R_BufferData_Resize(type, true, padsize);
3728
3729         // if the resize did not give us enough memory, fail
3730         if (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size)
3731                 Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3732
3733         mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3734         offset = (int)mem->current;
3735         mem->current += padsize;
3736
3737         // upload the data to the buffer at the chosen offset
3738         if (offset == 0)
3739                 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3740         R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3741
3742         // count the usage for stats
3743         r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3744         r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3745
3746         // return the buffer offset
3747         *returnbufferoffset = offset;
3748
3749         return mem->buffer;
3750 }
3751
3752 //==================================================================================
3753
3754 // LadyHavoc: animcache originally written by Echon, rewritten since then
3755
3756 /**
3757  * Animation cache prevents re-generating mesh data for an animated model
3758  * multiple times in one frame for lighting, shadowing, reflections, etc.
3759  */
3760
3761 void R_AnimCache_Free(void)
3762 {
3763 }
3764
3765 void R_AnimCache_ClearCache(void)
3766 {
3767         int i;
3768         entity_render_t *ent;
3769
3770         for (i = 0;i < r_refdef.scene.numentities;i++)
3771         {
3772                 ent = r_refdef.scene.entities[i];
3773                 ent->animcache_vertex3f = NULL;
3774                 ent->animcache_vertex3f_vertexbuffer = NULL;
3775                 ent->animcache_vertex3f_bufferoffset = 0;
3776                 ent->animcache_normal3f = NULL;
3777                 ent->animcache_normal3f_vertexbuffer = NULL;
3778                 ent->animcache_normal3f_bufferoffset = 0;
3779                 ent->animcache_svector3f = NULL;
3780                 ent->animcache_svector3f_vertexbuffer = NULL;
3781                 ent->animcache_svector3f_bufferoffset = 0;
3782                 ent->animcache_tvector3f = NULL;
3783                 ent->animcache_tvector3f_vertexbuffer = NULL;
3784                 ent->animcache_tvector3f_bufferoffset = 0;
3785                 ent->animcache_skeletaltransform3x4 = NULL;
3786                 ent->animcache_skeletaltransform3x4buffer = NULL;
3787                 ent->animcache_skeletaltransform3x4offset = 0;
3788                 ent->animcache_skeletaltransform3x4size = 0;
3789         }
3790 }
3791
3792 qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
3793 {
3794         dp_model_t *model = ent->model;
3795         int numvertices;
3796
3797         // see if this ent is worth caching
3798         if (!model || !model->Draw || !model->AnimateVertices)
3799                 return false;
3800         // nothing to cache if it contains no animations and has no skeleton
3801         if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3802                 return false;
3803         // see if it is already cached for gpuskeletal
3804         if (ent->animcache_skeletaltransform3x4)
3805                 return false;
3806         // see if it is already cached as a mesh
3807         if (ent->animcache_vertex3f)
3808         {
3809                 // check if we need to add normals or tangents
3810                 if (ent->animcache_normal3f)
3811                         wantnormals = false;
3812                 if (ent->animcache_svector3f)
3813                         wanttangents = false;
3814                 if (!wantnormals && !wanttangents)
3815                         return false;
3816         }
3817
3818         // check which kind of cache we need to generate
3819         if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3820         {
3821                 // cache the skeleton so the vertex shader can use it
3822                 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3823                 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3824                 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3825                 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3826                 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4); 
3827                 // note: this can fail if the buffer is at the grow limit
3828                 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3829                 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3830         }
3831         else if (ent->animcache_vertex3f)
3832         {
3833                 // mesh was already cached but we may need to add normals/tangents
3834                 // (this only happens with multiple views, reflections, cameras, etc)
3835                 if (wantnormals || wanttangents)
3836                 {
3837                         numvertices = model->surfmesh.num_vertices;
3838                         if (wantnormals)
3839                                 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3840                         if (wanttangents)
3841                         {
3842                                 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3843                                 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3844                         }
3845                         model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3846                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3847                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3848                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3849                 }
3850         }
3851         else
3852         {
3853                 // generate mesh cache
3854                 numvertices = model->surfmesh.num_vertices;
3855                 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3856                 if (wantnormals)
3857                         ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3858                 if (wanttangents)
3859                 {
3860                         ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3861                         ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3862                 }
3863                 model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
3864                 if (wantnormals || wanttangents)
3865                 {
3866                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3867                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3868                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3869                 }
3870                 r_refdef.stats[r_stat_animcache_shape_count] += 1;
3871                 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
3872                 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
3873         }
3874         return true;
3875 }
3876
3877 void R_AnimCache_CacheVisibleEntities(void)
3878 {
3879         int i;
3880
3881         // TODO: thread this
3882         // NOTE: R_PrepareRTLights() also caches entities
3883
3884         for (i = 0;i < r_refdef.scene.numentities;i++)
3885                 if (r_refdef.viewcache.entityvisible[i])
3886                         R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
3887 }
3888
3889 //==================================================================================
3890
3891 qboolean R_CanSeeBox(int numsamples, vec_t eyejitter, vec_t entboxenlarge, vec_t entboxexpand, vec_t pad, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs)
3892 {
3893         int i;
3894         vec3_t eyemins, eyemaxs;
3895         vec3_t boxmins, boxmaxs;
3896         vec3_t padmins, padmaxs;
3897         vec3_t start;
3898         vec3_t end;
3899         dp_model_t *model = r_refdef.scene.worldmodel;
3900         static vec3_t positions[] = {
3901                 { 0.5f, 0.5f, 0.5f },
3902                 { 0.0f, 0.0f, 0.0f },
3903                 { 0.0f, 0.0f, 1.0f },
3904                 { 0.0f, 1.0f, 0.0f },
3905                 { 0.0f, 1.0f, 1.0f },
3906                 { 1.0f, 0.0f, 0.0f },
3907                 { 1.0f, 0.0f, 1.0f },
3908                 { 1.0f, 1.0f, 0.0f },
3909                 { 1.0f, 1.0f, 1.0f },
3910         };
3911
3912         // sample count can be set to -1 to skip this logic, for flicker-prone objects
3913         if (numsamples < 0)
3914                 return true;
3915
3916         // view origin is not used for culling in portal/reflection/refraction renders or isometric views
3917         if (!r_refdef.view.usevieworiginculling)
3918                 return true;
3919
3920         if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
3921                 return true;
3922
3923         // expand the eye box a little
3924         eyemins[0] = eye[0] - eyejitter;
3925         eyemaxs[0] = eye[0] + eyejitter;
3926         eyemins[1] = eye[1] - eyejitter;
3927         eyemaxs[1] = eye[1] + eyejitter;
3928         eyemins[2] = eye[2] - eyejitter;
3929         eyemaxs[2] = eye[2] + eyejitter;
3930         // expand the box a little
3931         boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
3932         boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
3933         boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
3934         boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
3935         boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
3936         boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
3937         // make an even larger box for the acceptable area
3938         padmins[0] = boxmins[0] - pad;
3939         padmaxs[0] = boxmaxs[0] + pad;
3940         padmins[1] = boxmins[1] - pad;
3941         padmaxs[1] = boxmaxs[1] + pad;
3942         padmins[2] = boxmins[2] - pad;
3943         padmaxs[2] = boxmaxs[2] + pad;
3944
3945         // return true if eye overlaps enlarged box
3946         if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
3947                 return true;
3948
3949         // try specific positions in the box first - note that these can be cached
3950         if (r_cullentities_trace_entityocclusion.integer)
3951         {
3952                 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
3953                 {
3954                         VectorCopy(eye, start);
3955                         end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
3956                         end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
3957                         end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
3958                         //trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
3959                         trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
3960                         // not picky - if the trace ended anywhere in the box we're good
3961                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
3962                                 return true;
3963                 }
3964         }
3965         else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
3966                 return true;
3967
3968         // try various random positions
3969         for (i = 0; i < numsamples; i++)
3970         {
3971                 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
3972                 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
3973                 if (r_cullentities_trace_entityocclusion.integer)
3974                 {
3975                         trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
3976                         // not picky - if the trace ended anywhere in the box we're good
3977                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
3978                                 return true;
3979                 }
3980                 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
3981                         return true;
3982         }
3983
3984         return false;
3985 }
3986
3987
3988 static void R_View_UpdateEntityVisible (void)
3989 {
3990         int i;
3991         int renderimask;
3992         int samples;
3993         entity_render_t *ent;
3994
3995         if (r_refdef.envmap || r_fb.water.hideplayer)
3996                 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
3997         else if (chase_active.integer || r_fb.water.renderingscene)
3998                 renderimask = RENDER_VIEWMODEL;
3999         else
4000                 renderimask = RENDER_EXTERIORMODEL;
4001         if (!r_drawviewmodel.integer)
4002                 renderimask |= RENDER_VIEWMODEL;
4003         if (!r_drawexteriormodel.integer)
4004                 renderimask |= RENDER_EXTERIORMODEL;
4005         memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4006         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4007         {
4008                 // worldmodel can check visibility
4009                 for (i = 0;i < r_refdef.scene.numentities;i++)
4010                 {
4011                         ent = r_refdef.scene.entities[i];
4012                         if (!(ent->flags & renderimask))
4013                         if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
4014                         if ((ent->flags & (RENDER_NODEPTHTEST | RENDER_WORLDOBJECT | RENDER_VIEWMODEL)) || r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, ent->mins, ent->maxs))
4015                                 r_refdef.viewcache.entityvisible[i] = true;
4016                 }
4017         }
4018         else
4019         {
4020                 // no worldmodel or it can't check visibility
4021                 for (i = 0;i < r_refdef.scene.numentities;i++)
4022                 {
4023                         ent = r_refdef.scene.entities[i];
4024                         if (!(ent->flags & renderimask))
4025                         if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
4026                                 r_refdef.viewcache.entityvisible[i] = true;
4027                 }
4028         }
4029         if (r_cullentities_trace.integer)
4030         {
4031                 for (i = 0;i < r_refdef.scene.numentities;i++)
4032                 {
4033                         if (!r_refdef.viewcache.entityvisible[i])
4034                                 continue;
4035                         ent = r_refdef.scene.entities[i];
4036                         if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4037                         {
4038                                 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4039                                 if (R_CanSeeBox(samples, r_cullentities_trace_eyejitter.value, r_cullentities_trace_enlarge.value, r_cullentities_trace_expand.value, r_cullentities_trace_pad.value, r_refdef.view.origin, ent->mins, ent->maxs))
4040                                         ent->last_trace_visibility = realtime;
4041                                 if (ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
4042                                         r_refdef.viewcache.entityvisible[i] = 0;
4043                         }
4044                 }
4045         }
4046 }
4047
4048 /// only used if skyrendermasked, and normally returns false
4049 static int R_DrawBrushModelsSky (void)
4050 {
4051         int i, sky;
4052         entity_render_t *ent;
4053
4054         sky = false;
4055         for (i = 0;i < r_refdef.scene.numentities;i++)
4056         {
4057                 if (!r_refdef.viewcache.entityvisible[i])
4058                         continue;
4059                 ent = r_refdef.scene.entities[i];
4060                 if (!ent->model || !ent->model->DrawSky)
4061                         continue;
4062                 ent->model->DrawSky(ent);
4063                 sky = true;
4064         }
4065         return sky;
4066 }
4067
4068 static void R_DrawNoModel(entity_render_t *ent);
4069 static void R_DrawModels(void)
4070 {
4071         int i;
4072         entity_render_t *ent;
4073
4074         for (i = 0;i < r_refdef.scene.numentities;i++)
4075         {
4076                 if (!r_refdef.viewcache.entityvisible[i])
4077                         continue;
4078                 ent = r_refdef.scene.entities[i];
4079                 r_refdef.stats[r_stat_entities]++;
4080                 /*
4081                 if (ent->model && !strncmp(ent->model->name, "models/proto_", 13))
4082                 {
4083                         vec3_t f, l, u, o;
4084                         Matrix4x4_ToVectors(&ent->matrix, f, l, u, o);
4085                         Con_Printf("R_DrawModels\n");
4086                         Con_Printf("model %s O %f %f %f F %f %f %f L %f %f %f U %f %f %f\n", ent->model->name, o[0], o[1], o[2], f[0], f[1], f[2], l[0], l[1], l[2], u[0], u[1], u[2]);
4087                         Con_Printf("group: %i %f %i %f %i %f %i %f\n", ent->framegroupblend[0].frame, ent->framegroupblend[0].lerp, ent->framegroupblend[1].frame, ent->framegroupblend[1].lerp, ent->framegroupblend[2].frame, ent->framegroupblend[2].lerp, ent->framegroupblend[3].frame, ent->framegroupblend[3].lerp);
4088                         Con_Printf("blend: %i %f %i %f %i %f %i %f %i %f %i %f %i %f %i %f\n", ent->frameblend[0].subframe, ent->frameblend[0].lerp, ent->frameblend[1].subframe, ent->frameblend[1].lerp, ent->frameblend[2].subframe, ent->frameblend[2].lerp, ent->frameblend[3].subframe, ent->frameblend[3].lerp, ent->frameblend[4].subframe, ent->frameblend[4].lerp, ent->frameblend[5].subframe, ent->frameblend[5].lerp, ent->frameblend[6].subframe, ent->frameblend[6].lerp, ent->frameblend[7].subframe, ent->frameblend[7].lerp);
4089                 }
4090                 */
4091                 if (ent->model && ent->model->Draw != NULL)
4092                         ent->model->Draw(ent);
4093                 else
4094                         R_DrawNoModel(ent);
4095         }
4096 }
4097
4098 static void R_DrawModelsDepth(void)
4099 {
4100         int i;
4101         entity_render_t *ent;
4102
4103         for (i = 0;i < r_refdef.scene.numentities;i++)
4104         {
4105                 if (!r_refdef.viewcache.entityvisible[i])
4106                         continue;
4107                 ent = r_refdef.scene.entities[i];
4108                 if (ent->model && ent->model->DrawDepth != NULL)
4109                         ent->model->DrawDepth(ent);
4110         }
4111 }
4112
4113 static void R_DrawModelsDebug(void)
4114 {
4115         int i;
4116         entity_render_t *ent;
4117
4118         for (i = 0;i < r_refdef.scene.numentities;i++)
4119         {
4120                 if (!r_refdef.viewcache.entityvisible[i])
4121                         continue;
4122                 ent = r_refdef.scene.entities[i];
4123                 if (ent->model && ent->model->DrawDebug != NULL)
4124                         ent->model->DrawDebug(ent);
4125         }
4126 }
4127
4128 static void R_DrawModelsAddWaterPlanes(void)
4129 {
4130         int i;
4131         entity_render_t *ent;
4132
4133         for (i = 0;i < r_refdef.scene.numentities;i++)
4134         {
4135                 if (!r_refdef.viewcache.entityvisible[i])
4136                         continue;
4137                 ent = r_refdef.scene.entities[i];
4138                 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4139                         ent->model->DrawAddWaterPlanes(ent);
4140         }
4141 }
4142
4143 static float irisvecs[7][3] = {{0, 0, 0}, {-1, 0, 0}, {1, 0, 0}, {0, -1, 0}, {0, 1, 0}, {0, 0, -1}, {0, 0, 1}};
4144
4145 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4146 {
4147         if (r_hdr_irisadaptation.integer)
4148         {
4149                 vec3_t p;
4150                 vec3_t ambient;
4151                 vec3_t diffuse;
4152                 vec3_t diffusenormal;
4153                 vec3_t forward;
4154                 vec_t brightness = 0.0f;
4155                 vec_t goal;
4156                 vec_t current;
4157                 vec_t d;
4158                 int c;
4159                 VectorCopy(r_refdef.view.forward, forward);
4160                 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4161                 {
4162                         p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4163                         p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4164                         p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4165                         R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4166                         d = DotProduct(forward, diffusenormal);
4167                         brightness += VectorLength(ambient);
4168                         if (d > 0)
4169                                 brightness += d * VectorLength(diffuse);
4170                 }
4171                 brightness *= 1.0f / c;
4172                 brightness += 0.00001f; // make sure it's never zero
4173                 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4174                 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4175                 current = r_hdr_irisadaptation_value.value;
4176                 if (current < goal)
4177                         current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4178                 else if (current > goal)
4179                         current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4180                 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4181                         Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4182         }
4183         else if (r_hdr_irisadaptation_value.value != 1.0f)
4184                 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4185 }
4186
4187 static void R_View_SetFrustum(const int *scissor)
4188 {
4189         int i;
4190         double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4191         vec3_t forward, left, up, origin, v;
4192
4193         if(scissor)
4194         {
4195                 // flipped x coordinates (because x points left here)
4196                 fpx =  1.0 - 2.0 * (scissor[0]              - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4197                 fnx =  1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4198                 // non-flipped y coordinates
4199                 fny = -1.0 + 2.0 * (scissor[1]              - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4200                 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4201         }
4202
4203         // we can't trust r_refdef.view.forward and friends in reflected scenes
4204         Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4205
4206 #if 0
4207         r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4208         r_refdef.view.frustum[0].normal[1] = 0 - 0;
4209         r_refdef.view.frustum[0].normal[2] = -1 - 0;
4210         r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4211         r_refdef.view.frustum[1].normal[1] = 0 + 0;
4212         r_refdef.view.frustum[1].normal[2] = -1 + 0;
4213         r_refdef.view.frustum[2].normal[0] = 0 - 0;
4214         r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4215         r_refdef.view.frustum[2].normal[2] = -1 - 0;
4216         r_refdef.view.frustum[3].normal[0] = 0 + 0;
4217         r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4218         r_refdef.view.frustum[3].normal[2] = -1 + 0;
4219 #endif
4220
4221 #if 0
4222         zNear = r_refdef.nearclip;
4223         nudge = 1.0 - 1.0 / (1<<23);
4224         r_refdef.view.frustum[4].normal[0] = 0 - 0;
4225         r_refdef.view.frustum[4].normal[1] = 0 - 0;
4226         r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4227         r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4228         r_refdef.view.frustum[5].normal[0] = 0 + 0;
4229         r_refdef.view.frustum[5].normal[1] = 0 + 0;
4230         r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4231         r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4232 #endif
4233
4234
4235
4236 #if 0
4237         r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4238         r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4239         r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4240         r_refdef.view.frustum[0].dist = m[15] - m[12];
4241
4242         r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4243         r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4244         r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4245         r_refdef.view.frustum[1].dist = m[15] + m[12];
4246
4247         r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4248         r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4249         r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4250         r_refdef.view.frustum[2].dist = m[15] - m[13];
4251
4252         r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4253         r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4254         r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4255         r_refdef.view.frustum[3].dist = m[15] + m[13];
4256
4257         r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4258         r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4259         r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4260         r_refdef.view.frustum[4].dist = m[15] - m[14];
4261
4262         r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4263         r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4264         r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4265         r_refdef.view.frustum[5].dist = m[15] + m[14];
4266 #endif
4267
4268         if (r_refdef.view.useperspective)
4269         {
4270                 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4271                 VectorMAMAM(1024, forward, fnx * 1024.0 * r_refdef.view.frustum_x, left, fny * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[0]);
4272                 VectorMAMAM(1024, forward, fpx * 1024.0 * r_refdef.view.frustum_x, left, fny * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[1]);
4273                 VectorMAMAM(1024, forward, fnx * 1024.0 * r_refdef.view.frustum_x, left, fpy * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[2]);
4274                 VectorMAMAM(1024, forward, fpx * 1024.0 * r_refdef.view.frustum_x, left, fpy * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[3]);
4275
4276                 // then the normals from the corners relative to origin
4277                 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4278                 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4279                 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4280                 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4281
4282                 // in a NORMAL view, forward cross left == up
4283                 // in a REFLECTED view, forward cross left == down
4284                 // so our cross products above need to be adjusted for a left handed coordinate system
4285                 CrossProduct(forward, left, v);
4286                 if(DotProduct(v, up) < 0)
4287                 {
4288                         VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4289                         VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4290                         VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4291                         VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4292                 }
4293
4294                 // Leaving those out was a mistake, those were in the old code, and they
4295                 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4296                 // I couldn't reproduce it after adding those normalizations. --blub
4297                 VectorNormalize(r_refdef.view.frustum[0].normal);
4298                 VectorNormalize(r_refdef.view.frustum[1].normal);
4299                 VectorNormalize(r_refdef.view.frustum[2].normal);
4300                 VectorNormalize(r_refdef.view.frustum[3].normal);
4301
4302                 // make the corners absolute
4303                 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4304                 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4305                 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4306                 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4307
4308                 // one more normal
4309                 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4310
4311                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4312                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4313                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4314                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4315                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4316         }
4317         else
4318         {
4319                 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4320                 VectorScale(left,  1.0f, r_refdef.view.frustum[1].normal);
4321                 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4322                 VectorScale(up,  1.0f, r_refdef.view.frustum[3].normal);
4323                 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4324                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4325                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4326                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4327                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4328                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4329         }
4330         r_refdef.view.numfrustumplanes = 5;
4331
4332         if (r_refdef.view.useclipplane)
4333         {
4334                 r_refdef.view.numfrustumplanes = 6;
4335                 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4336         }
4337
4338         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4339                 PlaneClassify(r_refdef.view.frustum + i);
4340
4341         // LadyHavoc: note to all quake engine coders, Quake had a special case
4342         // for 90 degrees which assumed a square view (wrong), so I removed it,
4343         // Quake2 has it disabled as well.
4344
4345         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4346         //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4347         //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4348         //PlaneClassify(&frustum[0]);
4349
4350         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4351         //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4352         //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4353         //PlaneClassify(&frustum[1]);
4354
4355         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4356         //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4357         //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4358         //PlaneClassify(&frustum[2]);
4359
4360         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4361         //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4362         //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4363         //PlaneClassify(&frustum[3]);
4364
4365         // nearclip plane
4366         //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4367         //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4368         //PlaneClassify(&frustum[4]);
4369 }
4370
4371 static void R_View_UpdateWithScissor(const int *myscissor)
4372 {
4373         R_Main_ResizeViewCache();
4374         R_View_SetFrustum(myscissor);
4375         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4376         R_View_UpdateEntityVisible();
4377 }
4378
4379 static void R_View_Update(void)
4380 {
4381         R_Main_ResizeViewCache();
4382         R_View_SetFrustum(NULL);
4383         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4384         R_View_UpdateEntityVisible();
4385 }
4386
4387 float viewscalefpsadjusted = 1.0f;
4388
4389 static void R_GetScaledViewSize(int width, int height, int *outwidth, int *outheight)
4390 {
4391         float scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
4392         scale = bound(0.03125f, scale, 1.0f);
4393         *outwidth = (int)ceil(width * scale);
4394         *outheight = (int)ceil(height * scale);
4395 }
4396
4397 void R_SetupView(qboolean allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4398 {
4399         const float *customclipplane = NULL;
4400         float plane[4];
4401         int /*rtwidth,*/ rtheight;
4402         if (r_refdef.view.useclipplane && allowwaterclippingplane)
4403         {
4404                 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4405                 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4406                 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4407                 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4408                         dist = r_refdef.view.clipplane.dist;
4409                 plane[0] = r_refdef.view.clipplane.normal[0];
4410                 plane[1] = r_refdef.view.clipplane.normal[1];
4411                 plane[2] = r_refdef.view.clipplane.normal[2];
4412                 plane[3] = -dist;
4413                 customclipplane = plane;
4414         }
4415
4416         //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
4417         rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
4418
4419         if (!r_refdef.view.useperspective)
4420                 R_Viewport_InitOrtho3D(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane);
4421         else if (vid.stencil && r_useinfinitefarclip.integer)
4422                 R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane);
4423         else
4424                 R_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane);
4425         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4426         R_SetViewport(&r_refdef.view.viewport);
4427 }
4428
4429 void R_EntityMatrix(const matrix4x4_t *matrix)
4430 {
4431         if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4432         {
4433                 gl_modelmatrixchanged = false;
4434                 gl_modelmatrix = *matrix;
4435                 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4436                 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4437                 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4438                 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4439                 CHECKGLERROR
4440                 switch(vid.renderpath)
4441                 {
4442                 case RENDERPATH_GL32:
4443                 case RENDERPATH_GLES2:
4444                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4445                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4446                         break;
4447                 }
4448         }
4449 }
4450
4451 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4452 {
4453         r_viewport_t viewport;
4454
4455         CHECKGLERROR
4456
4457         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
4458         R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4459         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4460         R_SetViewport(&viewport);
4461         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4462         GL_Color(1, 1, 1, 1);
4463         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4464         GL_BlendFunc(GL_ONE, GL_ZERO);
4465         GL_ScissorTest(false);
4466         GL_DepthMask(false);
4467         GL_DepthRange(0, 1);
4468         GL_DepthTest(false);
4469         GL_DepthFunc(GL_LEQUAL);
4470         R_EntityMatrix(&identitymatrix);
4471         R_Mesh_ResetTextureState();
4472         GL_PolygonOffset(0, 0);
4473         switch(vid.renderpath)
4474         {
4475         case RENDERPATH_GL32:
4476         case RENDERPATH_GLES2:
4477                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4478                 break;
4479         }
4480         GL_CullFace(GL_NONE);
4481
4482         CHECKGLERROR
4483 }
4484
4485 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4486 {
4487         R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4488 }
4489
4490 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4491 {
4492         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4493         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4494         GL_Color(1, 1, 1, 1);
4495         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4496         GL_BlendFunc(GL_ONE, GL_ZERO);
4497         GL_ScissorTest(true);
4498         GL_DepthMask(true);
4499         GL_DepthRange(0, 1);
4500         GL_DepthTest(true);
4501         GL_DepthFunc(GL_LEQUAL);
4502         R_EntityMatrix(&identitymatrix);
4503         R_Mesh_ResetTextureState();
4504         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4505         switch(vid.renderpath)
4506         {
4507         case RENDERPATH_GL32:
4508         case RENDERPATH_GLES2:
4509                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4510                 break;
4511         }
4512         GL_CullFace(r_refdef.view.cullface_back);
4513 }
4514
4515 /*
4516 ================
4517 R_RenderView_UpdateViewVectors
4518 ================
4519 */
4520 void R_RenderView_UpdateViewVectors(void)
4521 {
4522         // break apart the view matrix into vectors for various purposes
4523         // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4524         // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4525         Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4526         VectorNegate(r_refdef.view.left, r_refdef.view.right);
4527         // make an inverted copy of the view matrix for tracking sprites
4528         Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4529 }
4530
4531 void R_RenderTarget_FreeUnused(qboolean force)
4532 {
4533         unsigned int i, j, end;
4534         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4535         for (i = 0; i < end; i++)
4536         {
4537                 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4538                 // free resources for rendertargets that have not been used for a while
4539                 // (note: this check is run after the frame render, so any targets used
4540                 // this frame will not be affected even at low framerates)
4541                 if (r && (realtime - r->lastusetime > 0.2 || force))
4542                 {
4543                         if (r->fbo)
4544                                 R_Mesh_DestroyFramebufferObject(r->fbo);
4545                         for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4546                                 if (r->colortexture[j])
4547                                         R_FreeTexture(r->colortexture[j]);
4548                         if (r->depthtexture)
4549                                 R_FreeTexture(r->depthtexture);
4550                         Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4551                 }
4552         }
4553 }
4554
4555 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4556 {
4557         float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4558         x1 = x * iw;
4559         x2 = (x + w) * iw;
4560         y1 = (th - y) * ih;
4561         y2 = (th - y - h) * ih;
4562         texcoord2f[0] = x1;
4563         texcoord2f[2] = x2;
4564         texcoord2f[4] = x2;
4565         texcoord2f[6] = x1;
4566         texcoord2f[1] = y1;
4567         texcoord2f[3] = y1;
4568         texcoord2f[5] = y2;
4569         texcoord2f[7] = y2;
4570 }
4571
4572 r_rendertarget_t *R_RenderTarget_Get(int texturewidth, int textureheight, textype_t depthtextype, qboolean depthisrenderbuffer, textype_t colortextype0, textype_t colortextype1, textype_t colortextype2, textype_t colortextype3)
4573 {
4574         unsigned int i, j, end;
4575         r_rendertarget_t *r = NULL;
4576         char vabuf[256];
4577         // first try to reuse an existing slot if possible
4578         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4579         for (i = 0; i < end; i++)
4580         {
4581                 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4582                 if (r && r->lastusetime != realtime && r->texturewidth == texturewidth && r->textureheight == textureheight && r->depthtextype == depthtextype && r->colortextype[0] == colortextype0 && r->colortextype[1] == colortextype1 && r->colortextype[2] == colortextype2 && r->colortextype[3] == colortextype3)
4583                         break;
4584         }
4585         if (i == end)
4586         {
4587                 // no unused exact match found, so we have to make one in the first unused slot
4588                 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4589                 r->texturewidth = texturewidth;
4590                 r->textureheight = textureheight;
4591                 r->colortextype[0] = colortextype0;
4592                 r->colortextype[1] = colortextype1;
4593                 r->colortextype[2] = colortextype2;
4594                 r->colortextype[3] = colortextype3;
4595                 r->depthtextype = depthtextype;
4596                 r->depthisrenderbuffer = depthisrenderbuffer;
4597                 for (j = 0; j < 4; j++)
4598                         if (r->colortextype[j])
4599                                 r->colortexture[j] = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "rendertarget%i_%i_type%i", i, j, (int)r->colortextype[j]), r->texturewidth, r->textureheight, NULL, r->colortextype[j], TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
4600                 if (r->depthtextype)
4601                 {
4602                         if (r->depthisrenderbuffer)
4603                                 r->depthtexture = R_LoadTextureRenderBuffer(r_main_texturepool, va(vabuf, sizeof(vabuf), "renderbuffer%i_depth_type%i", i, (int)r->depthtextype), r->texturewidth, r->textureheight, r->depthtextype);
4604                         else
4605                                 r->depthtexture = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "rendertarget%i_depth_type%i", i, j, (int)r->depthtextype), r->texturewidth, r->textureheight, NULL, r->depthtextype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
4606                 }
4607                 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4608         }
4609         r_refdef.stats[r_stat_rendertargets_used]++;
4610         r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4611         r->lastusetime = realtime;
4612         R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4613         return r;
4614 }
4615
4616 static void R_Water_StartFrame(void)
4617 {
4618         int waterwidth, waterheight;
4619
4620         if (vid.width > (int)vid.maxtexturesize_2d || vid.height > (int)vid.maxtexturesize_2d)
4621                 return;
4622
4623         // set waterwidth and waterheight to the water resolution that will be
4624         // used (often less than the screen resolution for faster rendering)
4625         waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width);
4626         waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height);
4627         R_GetScaledViewSize(waterwidth, waterheight, &waterwidth, &waterheight);
4628
4629         if (!r_water.integer || r_showsurfaces.integer)
4630                 waterwidth = waterheight = 0;
4631
4632         // set up variables that will be used in shader setup
4633         r_fb.water.waterwidth = waterwidth;
4634         r_fb.water.waterheight = waterheight;
4635         r_fb.water.texturewidth = waterwidth;
4636         r_fb.water.textureheight = waterheight;
4637         r_fb.water.camerawidth = waterwidth;
4638         r_fb.water.cameraheight = waterheight;
4639         r_fb.water.screenscale[0] = 0.5f;
4640         r_fb.water.screenscale[1] = 0.5f;
4641         r_fb.water.screencenter[0] = 0.5f;
4642         r_fb.water.screencenter[1] = 0.5f;
4643         r_fb.water.enabled = waterwidth != 0;
4644
4645         r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4646         r_fb.water.numwaterplanes = 0;
4647 }
4648
4649 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4650 {
4651         int planeindex, bestplaneindex, vertexindex;
4652         vec3_t mins, maxs, normal, center, v, n;
4653         vec_t planescore, bestplanescore;
4654         mplane_t plane;
4655         r_waterstate_waterplane_t *p;
4656         texture_t *t = R_GetCurrentTexture(surface->texture);
4657
4658         rsurface.texture = t;
4659         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4660         // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4661         if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4662                 return;
4663         // average the vertex normals, find the surface bounds (after deformvertexes)
4664         Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4665         Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4666         VectorCopy(n, normal);
4667         VectorCopy(v, mins);
4668         VectorCopy(v, maxs);
4669         for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4670         {
4671                 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4672                 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4673                 VectorAdd(normal, n, normal);
4674                 mins[0] = min(mins[0], v[0]);
4675                 mins[1] = min(mins[1], v[1]);
4676                 mins[2] = min(mins[2], v[2]);
4677                 maxs[0] = max(maxs[0], v[0]);
4678                 maxs[1] = max(maxs[1], v[1]);
4679                 maxs[2] = max(maxs[2], v[2]);
4680         }
4681         VectorNormalize(normal);
4682         VectorMAM(0.5f, mins, 0.5f, maxs, center);
4683
4684         VectorCopy(normal, plane.normal);
4685         VectorNormalize(plane.normal);
4686         plane.dist = DotProduct(center, plane.normal);
4687         PlaneClassify(&plane);
4688         if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4689         {
4690                 // skip backfaces (except if nocullface is set)
4691 //              if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4692 //                      return;
4693                 VectorNegate(plane.normal, plane.normal);
4694                 plane.dist *= -1;
4695                 PlaneClassify(&plane);
4696         }
4697
4698
4699         // find a matching plane if there is one
4700         bestplaneindex = -1;
4701         bestplanescore = 1048576.0f;
4702         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4703         {
4704                 if(p->camera_entity == t->camera_entity)
4705                 {
4706                         planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4707                         if (bestplaneindex < 0 || bestplanescore > planescore)
4708                         {
4709                                 bestplaneindex = planeindex;
4710                                 bestplanescore = planescore;
4711                         }
4712                 }
4713         }
4714         planeindex = bestplaneindex;
4715
4716         // if this surface does not fit any known plane rendered this frame, add one
4717         if (planeindex < 0 || bestplanescore > 0.001f)
4718         {
4719                 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4720                 {
4721                         // store the new plane
4722                         planeindex = r_fb.water.numwaterplanes++;
4723                         p = r_fb.water.waterplanes + planeindex;
4724                         p->plane = plane;
4725                         // clear materialflags and pvs
4726                         p->materialflags = 0;
4727                         p->pvsvalid = false;
4728                         p->camera_entity = t->camera_entity;
4729                         VectorCopy(mins, p->mins);
4730                         VectorCopy(maxs, p->maxs);
4731                 }
4732                 else
4733                 {
4734                         // We're totally screwed.
4735                         return;
4736                 }
4737         }
4738         else
4739         {
4740                 // merge mins/maxs when we're adding this surface to the plane
4741                 p = r_fb.water.waterplanes + planeindex;
4742                 p->mins[0] = min(p->mins[0], mins[0]);
4743                 p->mins[1] = min(p->mins[1], mins[1]);
4744                 p->mins[2] = min(p->mins[2], mins[2]);
4745                 p->maxs[0] = max(p->maxs[0], maxs[0]);
4746                 p->maxs[1] = max(p->maxs[1], maxs[1]);
4747                 p->maxs[2] = max(p->maxs[2], maxs[2]);
4748         }
4749         // merge this surface's materialflags into the waterplane
4750         p->materialflags |= t->currentmaterialflags;
4751         if(!(p->materialflags & MATERIALFLAG_CAMERA))
4752         {
4753                 // merge this surface's PVS into the waterplane
4754                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4755                  && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4756                 {
4757                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4758                         p->pvsvalid = true;
4759                 }
4760         }
4761 }
4762
4763 extern cvar_t r_drawparticles;
4764 extern cvar_t r_drawdecals;
4765
4766 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4767 {
4768         int myscissor[4];
4769         r_refdef_view_t originalview;
4770         r_refdef_view_t myview;
4771         int planeindex, qualityreduction = 0, old_r_dynamic = 0, old_r_shadows = 0, old_r_worldrtlight = 0, old_r_dlight = 0, old_r_particles = 0, old_r_decals = 0;
4772         r_waterstate_waterplane_t *p;
4773         vec3_t visorigin;
4774         r_rendertarget_t *rt;
4775
4776         originalview = r_refdef.view;
4777
4778         // lowquality hack, temporarily shut down some cvars and restore afterwards
4779         qualityreduction = r_water_lowquality.integer;
4780         if (qualityreduction > 0)
4781         {
4782                 if (qualityreduction >= 1)
4783                 {
4784                         old_r_shadows = r_shadows.integer;
4785                         old_r_worldrtlight = r_shadow_realtime_world.integer;
4786                         old_r_dlight = r_shadow_realtime_dlight.integer;
4787                         Cvar_SetValueQuick(&r_shadows, 0);
4788                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4789                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4790                 }
4791                 if (qualityreduction >= 2)
4792                 {
4793                         old_r_dynamic = r_dynamic.integer;
4794                         old_r_particles = r_drawparticles.integer;
4795                         old_r_decals = r_drawdecals.integer;
4796                         Cvar_SetValueQuick(&r_dynamic, 0);
4797                         Cvar_SetValueQuick(&r_drawparticles, 0);
4798                         Cvar_SetValueQuick(&r_drawdecals, 0);
4799                 }
4800         }
4801
4802         for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4803         {
4804                 p->rt_reflection = NULL;
4805                 p->rt_refraction = NULL;
4806                 p->rt_camera = NULL;
4807         }
4808
4809         // render views
4810         r_refdef.view = originalview;
4811         r_refdef.view.showdebug = false;
4812         r_refdef.view.width = r_fb.water.waterwidth;
4813         r_refdef.view.height = r_fb.water.waterheight;
4814         r_refdef.view.useclipplane = true;
4815         myview = r_refdef.view;
4816         r_fb.water.renderingscene = true;
4817         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4818         {
4819                 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4820                         continue;
4821
4822                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4823                 {
4824                         rt = R_RenderTarget_Get(r_fb.water.waterwidth, r_fb.water.waterheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, r_fb.rt_screen->colortextype[0], TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
4825                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4826                                 goto error;
4827                         r_refdef.view = myview;
4828                         Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4829                         Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4830                         if(r_water_scissormode.integer)
4831                         {
4832                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4833                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4834                                 {
4835                                         p->rt_reflection = NULL;
4836                                         p->rt_refraction = NULL;
4837                                         p->rt_camera = NULL;
4838                                         continue;
4839                                 }
4840                         }
4841
4842                         r_refdef.view.clipplane = p->plane;
4843                         // reflected view origin may be in solid, so don't cull with it
4844                         r_refdef.view.usevieworiginculling = false;
4845                         // reverse the cullface settings for this render
4846                         r_refdef.view.cullface_front = GL_FRONT;
4847                         r_refdef.view.cullface_back = GL_BACK;
4848                         // combined pvs (based on what can be seen from each surface center)
4849                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4850                         {
4851                                 r_refdef.view.usecustompvs = true;
4852                                 if (p->pvsvalid)
4853                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4854                                 else
4855                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4856                         }
4857
4858                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4859                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4860                         GL_ScissorTest(false);
4861                         R_ClearScreen(r_refdef.fogenabled);
4862                         GL_ScissorTest(true);
4863                         if(r_water_scissormode.integer & 2)
4864                                 R_View_UpdateWithScissor(myscissor);
4865                         else
4866                                 R_View_Update();
4867                         R_AnimCache_CacheVisibleEntities();
4868                         if(r_water_scissormode.integer & 1)
4869                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4870                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4871
4872                         r_fb.water.hideplayer = false;
4873                         p->rt_reflection = rt;
4874                 }
4875
4876                 // render the normal view scene and copy into texture
4877                 // (except that a clipping plane should be used to hide everything on one side of the water, and the viewer's weapon model should be omitted)
4878                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
4879                 {
4880                         rt = R_RenderTarget_Get(r_fb.water.waterwidth, r_fb.water.waterheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, r_fb.rt_screen->colortextype[0], TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
4881                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4882                                 goto error;
4883                         r_refdef.view = myview;
4884                         if(r_water_scissormode.integer)
4885                         {
4886                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4887                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4888                                 {
4889                                         p->rt_reflection = NULL;
4890                                         p->rt_refraction = NULL;
4891                                         p->rt_camera = NULL;
4892                                         continue;
4893                                 }
4894                         }
4895
4896                         // combined pvs (based on what can be seen from each surface center)
4897                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4898                         {
4899                                 r_refdef.view.usecustompvs = true;
4900                                 if (p->pvsvalid)
4901                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4902                                 else
4903                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4904                         }
4905
4906                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
4907
4908                         r_refdef.view.clipplane = p->plane;
4909                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
4910                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
4911
4912                         if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
4913                         {
4914                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
4915                                 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
4916                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
4917                                 R_RenderView_UpdateViewVectors();
4918                                 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
4919                                 {
4920                                         r_refdef.view.usecustompvs = true;
4921                                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, visorigin, 2, r_refdef.viewcache.world_pvsbits, (r_refdef.viewcache.world_numclusters+7)>>3, false);
4922                                 }
4923                         }
4924
4925                         PlaneClassify(&r_refdef.view.clipplane);
4926
4927                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4928                         GL_ScissorTest(false);
4929                         R_ClearScreen(r_refdef.fogenabled);
4930                         GL_ScissorTest(true);
4931                         if(r_water_scissormode.integer & 2)
4932                                 R_View_UpdateWithScissor(myscissor);
4933                         else
4934                                 R_View_Update();
4935                         R_AnimCache_CacheVisibleEntities();
4936                         if(r_water_scissormode.integer & 1)
4937                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4938                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4939
4940                         r_fb.water.hideplayer = false;
4941                         p->rt_refraction = rt;
4942                 }
4943                 else if (p->materialflags & MATERIALFLAG_CAMERA)
4944                 {
4945                         rt = R_RenderTarget_Get(r_fb.water.waterwidth, r_fb.water.waterheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, r_fb.rt_screen->colortextype[0], TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
4946                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4947                                 goto error;
4948                         r_refdef.view = myview;
4949
4950                         r_refdef.view.clipplane = p->plane;
4951                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
4952                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
4953
4954                         r_refdef.view.width = r_fb.water.camerawidth;
4955                         r_refdef.view.height = r_fb.water.cameraheight;
4956                         r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
4957                         r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
4958                         r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
4959                         r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
4960
4961                         if(p->camera_entity)
4962                         {
4963                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
4964                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
4965                         }
4966
4967                         // note: all of the view is used for displaying... so
4968                         // there is no use in scissoring
4969
4970                         // reverse the cullface settings for this render
4971                         r_refdef.view.cullface_front = GL_FRONT;
4972                         r_refdef.view.cullface_back = GL_BACK;
4973                         // also reverse the view matrix
4974                         Matrix4x4_ConcatScale3(&r_refdef.view.matrix, 1, 1, -1); // this serves to invert texcoords in the result, as the copied texture is mapped the wrong way round
4975                         R_RenderView_UpdateViewVectors();
4976                         if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
4977                         {
4978                                 r_refdef.view.usecustompvs = true;
4979                                 r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, visorigin, 2, r_refdef.viewcache.world_pvsbits, (r_refdef.viewcache.world_numclusters+7)>>3, false);
4980                         }
4981                         
4982                         // camera needs no clipplane
4983                         r_refdef.view.useclipplane = false;
4984                         // TODO: is the camera origin always valid?  if so we don't need to clear this
4985                         r_refdef.view.usevieworiginculling = false;
4986
4987                         PlaneClassify(&r_refdef.view.clipplane);
4988
4989                         r_fb.water.hideplayer = false;
4990
4991                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4992                         GL_ScissorTest(false);
4993                         R_ClearScreen(r_refdef.fogenabled);
4994                         GL_ScissorTest(true);
4995                         R_View_Update();
4996                         R_AnimCache_CacheVisibleEntities();
4997                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4998
4999                         r_fb.water.hideplayer = false;
5000                         p->rt_camera = rt;
5001                 }
5002
5003         }
5004         r_fb.water.renderingscene = false;
5005         r_refdef.view = originalview;
5006         R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5007         R_View_Update();
5008         R_AnimCache_CacheVisibleEntities();
5009         goto finish;
5010 error:
5011         r_refdef.view = originalview;
5012         r_fb.water.renderingscene = false;
5013         Cvar_SetValueQuick(&r_water, 0);
5014         Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed!  Turned off r_water.\n");
5015 finish:
5016         // lowquality hack, restore cvars
5017         if (qualityreduction > 0)
5018         {
5019                 if (qualityreduction >= 1)
5020                 {
5021                         Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5022                         Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5023                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5024                 }
5025                 if (qualityreduction >= 2)
5026                 {
5027                         Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5028                         Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5029                         Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5030                 }
5031         }
5032 }
5033
5034 static void R_Bloom_StartFrame(void)
5035 {
5036         int screentexturewidth, screentextureheight;
5037         int viewwidth, viewheight;
5038         textype_t textype = TEXTYPE_COLORBUFFER;
5039
5040         // clear the pointers to rendertargets from last frame as they're stale
5041         r_fb.rt_screen = NULL;
5042         r_fb.rt_bloom = NULL;
5043
5044         switch (vid.renderpath)
5045         {
5046         case RENDERPATH_GL32:
5047                 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5048                 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5049                 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5050                 break;
5051         case RENDERPATH_GLES2:
5052                 r_fb.usedepthtextures = false;
5053                 break;
5054         }
5055
5056         if (r_viewscale_fpsscaling.integer)
5057         {
5058                 double actualframetime;
5059                 double targetframetime;
5060                 double adjust;
5061                 actualframetime = r_refdef.lastdrawscreentime;
5062                 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5063                 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5064                 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5065                 if (r_viewscale_fpsscaling_stepsize.value > 0)
5066                         adjust = (int)(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5067                 viewscalefpsadjusted += adjust;
5068                 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5069         }
5070         else
5071                 viewscalefpsadjusted = 1.0f;
5072
5073         R_GetScaledViewSize(r_refdef.view.width, r_refdef.view.height, &viewwidth, &viewheight);
5074
5075         // set bloomwidth and bloomheight to the bloom resolution that will be
5076         // used (often less than the screen resolution for faster rendering)
5077         r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, vid.width);
5078         r_fb.bloomheight = r_fb.bloomwidth * vid.height / vid.width;
5079         r_fb.bloomheight = bound(1, r_fb.bloomheight, vid.height);
5080         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5081         r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5082
5083         // calculate desired texture sizes
5084         screentexturewidth = viewwidth;
5085         screentextureheight = viewheight;
5086
5087         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))
5088         {
5089                 Cvar_SetValueQuick(&r_bloom, 0);
5090                 Cvar_SetValueQuick(&r_motionblur, 0);
5091                 Cvar_SetValueQuick(&r_damageblur, 0);
5092         }
5093
5094         // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5095         if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5096         {
5097                 if (r_fb.ghosttexture)
5098                         R_FreeTexture(r_fb.ghosttexture);
5099                 r_fb.ghosttexture = NULL;
5100
5101                 r_fb.screentexturewidth = screentexturewidth;
5102                 r_fb.screentextureheight = screentextureheight;
5103                 r_fb.textype = textype;
5104
5105                 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5106                 {
5107                         if (r_motionblur.value > 0 || r_damageblur.value > 0)
5108                                 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);
5109                         r_fb.ghosttexture_valid = false;
5110                 }
5111         }
5112
5113         if (r_bloom.integer)
5114         {
5115                 // bloom texture is a different resolution
5116                 r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.width);
5117                 r_fb.bloomheight = r_fb.bloomwidth * r_refdef.view.height / r_refdef.view.width;
5118                 r_fb.bloomheight = bound(1, r_fb.bloomheight, r_refdef.view.height);
5119         }
5120         else
5121                 r_fb.bloomwidth = r_fb.bloomheight = 0;
5122
5123         r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5124
5125         r_refdef.view.clear = true;
5126 }
5127
5128 static void R_Bloom_MakeTexture(void)
5129 {
5130         int x, range, dir;
5131         float xoffset, yoffset, r, brighten;
5132         float colorscale = r_bloom_colorscale.value;
5133         r_viewport_t bloomviewport;
5134         r_rendertarget_t *prev, *cur;
5135         textype_t textype = r_fb.rt_screen->colortextype[0];
5136
5137         r_refdef.stats[r_stat_bloom]++;
5138
5139         R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5140
5141         // scale down screen texture to the bloom texture size
5142         CHECKGLERROR
5143         prev = r_fb.rt_screen;
5144         cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5145         R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5146         R_SetViewport(&bloomviewport);
5147         GL_CullFace(GL_NONE);
5148         GL_DepthTest(false);
5149         GL_BlendFunc(GL_ONE, GL_ZERO);
5150         GL_Color(colorscale, colorscale, colorscale, 1);
5151         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5152         // TODO: do boxfilter scale-down in shader?
5153         R_SetupShader_Generic(prev->colortexture[0], false, true, true);
5154         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5155         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5156         // we now have a properly scaled bloom image
5157
5158         // multiply bloom image by itself as many times as desired to darken it
5159         // TODO: if people actually use this it could be done more quickly in the previous shader pass
5160         for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5161         {
5162                 prev = cur;
5163                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5164                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5165                 x *= 2;
5166                 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5167                 if(x <= 2)
5168                         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0);
5169                 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5170                 GL_Color(1,1,1,1); // no fix factor supported here
5171                 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5172                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5173                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5174                 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5175         }
5176         CHECKGLERROR
5177
5178         range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5179         brighten = r_bloom_brighten.value;
5180         brighten = sqrt(brighten);
5181         if(range >= 1)
5182                 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5183
5184         for (dir = 0;dir < 2;dir++)
5185         {
5186                 prev = cur;
5187                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5188                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5189                 // blend on at multiple vertical offsets to achieve a vertical blur
5190                 // TODO: do offset blends using GLSL
5191                 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5192                 CHECKGLERROR
5193                 GL_BlendFunc(GL_ONE, GL_ZERO);
5194                 CHECKGLERROR
5195                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5196                 CHECKGLERROR
5197                 for (x = -range;x <= range;x++)
5198                 {
5199                         if (!dir){xoffset = 0;yoffset = x;}
5200                         else {xoffset = x;yoffset = 0;}
5201                         xoffset /= (float)prev->texturewidth;
5202                         yoffset /= (float)prev->textureheight;
5203                         // compute a texcoord array with the specified x and y offset
5204                         r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5205                         r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5206                         r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5207                         r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5208                         r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5209                         r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5210                         r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5211                         r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5212                         // this r value looks like a 'dot' particle, fading sharply to
5213                         // black at the edges
5214                         // (probably not realistic but looks good enough)
5215                         //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5216                         //r = brighten/(range*2+1);
5217                         r = brighten / (range * 2 + 1);
5218                         if(range >= 1)
5219                                 r *= (1 - x*x/(float)((range+1)*(range+1)));
5220                         if (r <= 0)
5221                                 continue;
5222                         CHECKGLERROR
5223                         GL_Color(r, r, r, 1);
5224                         CHECKGLERROR
5225                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5226                         CHECKGLERROR
5227                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5228                         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5229                         CHECKGLERROR
5230                         GL_BlendFunc(GL_ONE, GL_ONE);
5231                         CHECKGLERROR
5232                 }
5233         }
5234
5235         // now we have the bloom image, so keep track of it
5236         r_fb.rt_bloom = cur;
5237 }
5238
5239 static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5240 {
5241         dpuint64 permutation;
5242         float uservecs[4][4];
5243         rtexture_t *viewtexture;
5244         rtexture_t *bloomtexture;
5245
5246         R_EntityMatrix(&identitymatrix);
5247
5248         if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
5249         {
5250                 // declare variables
5251                 float blur_factor, blur_mouseaccel, blur_velocity;
5252                 static float blur_average; 
5253                 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5254
5255                 // set a goal for the factoring
5256                 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value) 
5257                         / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5258                 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value) 
5259                         / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5260                 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value) 
5261                         + (blur_mouseaccel * r_motionblur_mousefactor.value));
5262
5263                 // from the goal, pick an averaged value between goal and last value
5264                 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5265                 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5266
5267                 // enforce minimum amount of blur 
5268                 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5269
5270                 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5271
5272                 // calculate values into a standard alpha
5273                 cl.motionbluralpha = 1 - exp(-
5274                                 (
5275                                         (r_motionblur.value * blur_factor / 80)
5276                                         +
5277                                         (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5278                                 )
5279                                 /
5280                                 max(0.0001, cl.time - cl.oldtime) // fps independent
5281                                 );
5282
5283                 // randomization for the blur value to combat persistent ghosting
5284                 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5285                 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5286
5287                 // apply the blur
5288                 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5289                 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5290                 {
5291                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5292                         GL_Color(1, 1, 1, cl.motionbluralpha);
5293                         R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5294                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5295                         R_SetupShader_Generic(r_fb.ghosttexture, false, true, true);
5296                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5297                         r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5298                 }
5299
5300                 // updates old view angles for next pass
5301                 VectorCopy(cl.viewangles, blur_oldangles);
5302
5303                 // copy view into the ghost texture
5304                 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5305                 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5306                 r_fb.ghosttexture_valid = true;
5307         }
5308
5309         if (r_fb.bloomwidth)
5310         {
5311                 // make the bloom texture
5312                 R_Bloom_MakeTexture();
5313         }
5314
5315 #if _MSC_VER >= 1400
5316 #define sscanf sscanf_s
5317 #endif
5318         memset(uservecs, 0, sizeof(uservecs));
5319         if (r_glsl_postprocess_uservec1_enable.integer)
5320                 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5321         if (r_glsl_postprocess_uservec2_enable.integer)
5322                 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5323         if (r_glsl_postprocess_uservec3_enable.integer)
5324                 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5325         if (r_glsl_postprocess_uservec4_enable.integer)
5326                 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5327
5328         // render to the screen fbo
5329         R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5330         GL_Color(1, 1, 1, 1);
5331         GL_BlendFunc(GL_ONE, GL_ZERO);
5332
5333         viewtexture = r_fb.rt_screen->colortexture[0];
5334         bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5335
5336         if (r_rendertarget_debug.integer >= 0)
5337         {
5338                 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5339                 if (rt && rt->colortexture[0])
5340                 {
5341                         viewtexture = rt->colortexture[0];
5342                         bloomtexture = NULL;
5343                 }
5344         }
5345
5346         R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5347         switch(vid.renderpath)
5348         {
5349         case RENDERPATH_GL32:
5350         case RENDERPATH_GLES2:
5351                 permutation =
5352                         (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5353                         | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5354                         | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5355                         | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5356                         | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5357                 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5358                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First     , viewtexture);
5359                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second    , bloomtexture);
5360                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps       );
5361                 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]);
5362                 if (r_glsl_permutation->loc_PixelSize               >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize         , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5363                 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]);
5364                 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]);
5365                 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]);
5366                 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]);
5367                 if (r_glsl_permutation->loc_Saturation              >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation        , r_glsl_saturation.value);
5368                 if (r_glsl_permutation->loc_PixelToScreenTexCoord   >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
5369                 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);
5370                 break;
5371         }
5372         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5373         r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5374 }
5375
5376 matrix4x4_t r_waterscrollmatrix;
5377
5378 void R_UpdateFog(void)
5379 {
5380         // Nehahra fog
5381         if (gamemode == GAME_NEHAHRA)
5382         {
5383                 if (gl_fogenable.integer)
5384                 {
5385                         r_refdef.oldgl_fogenable = true;
5386                         r_refdef.fog_density = gl_fogdensity.value;
5387                         r_refdef.fog_red = gl_fogred.value;
5388                         r_refdef.fog_green = gl_foggreen.value;
5389                         r_refdef.fog_blue = gl_fogblue.value;
5390                         r_refdef.fog_alpha = 1;
5391                         r_refdef.fog_start = 0;
5392                         r_refdef.fog_end = gl_skyclip.value;
5393                         r_refdef.fog_height = 1<<30;
5394                         r_refdef.fog_fadedepth = 128;
5395                 }
5396                 else if (r_refdef.oldgl_fogenable)
5397                 {
5398                         r_refdef.oldgl_fogenable = false;
5399                         r_refdef.fog_density = 0;
5400                         r_refdef.fog_red = 0;
5401                         r_refdef.fog_green = 0;
5402                         r_refdef.fog_blue = 0;
5403                         r_refdef.fog_alpha = 0;
5404                         r_refdef.fog_start = 0;
5405                         r_refdef.fog_end = 0;
5406                         r_refdef.fog_height = 1<<30;
5407                         r_refdef.fog_fadedepth = 128;
5408                 }
5409         }
5410
5411         // fog parms
5412         r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5413         r_refdef.fog_start = max(0, r_refdef.fog_start);
5414         r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5415
5416         if (r_refdef.fog_density && r_drawfog.integer)
5417         {
5418                 r_refdef.fogenabled = true;
5419                 // this is the point where the fog reaches 0.9986 alpha, which we
5420                 // consider a good enough cutoff point for the texture
5421                 // (0.9986 * 256 == 255.6)
5422                 if (r_fog_exp2.integer)
5423                         r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5424                 else
5425                         r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5426                 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5427                 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5428                 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5429                 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5430                         R_BuildFogHeightTexture();
5431                 // fog color was already set
5432                 // update the fog texture
5433                 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)
5434                         R_BuildFogTexture();
5435                 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5436                 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5437         }
5438         else
5439                 r_refdef.fogenabled = false;
5440
5441         // fog color
5442         if (r_refdef.fog_density)
5443         {
5444                 r_refdef.fogcolor[0] = r_refdef.fog_red;
5445                 r_refdef.fogcolor[1] = r_refdef.fog_green;
5446                 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5447
5448                 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5449                 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5450                 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5451                 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5452
5453                 {
5454                         vec3_t fogvec;
5455                         VectorCopy(r_refdef.fogcolor, fogvec);
5456                         //   color.rgb *= ContrastBoost * SceneBrightness;
5457                         VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5458                         r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5459                         r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5460                         r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5461                 }
5462         }
5463 }
5464
5465 void R_UpdateVariables(void)
5466 {
5467         R_Textures_Frame();
5468
5469         r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5470
5471         r_refdef.farclip = r_farclip_base.value;
5472         if (r_refdef.scene.worldmodel)
5473                 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5474         r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5475
5476         if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5477                 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5478         r_refdef.polygonfactor = 0;
5479         r_refdef.polygonoffset = 0;
5480
5481         r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5482         r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5483         r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5484         r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5485         r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5486         if (r_refdef.scene.worldmodel)
5487         {
5488                 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5489         }
5490         if (r_showsurfaces.integer)
5491         {
5492                 r_refdef.scene.rtworld = false;
5493                 r_refdef.scene.rtworldshadows = false;
5494                 r_refdef.scene.rtdlight = false;
5495                 r_refdef.scene.rtdlightshadows = false;
5496                 r_refdef.scene.lightmapintensity = 0;
5497         }
5498
5499         r_gpuskeletal = false;
5500         switch(vid.renderpath)
5501         {
5502         case RENDERPATH_GL32:
5503                 r_gpuskeletal = r_glsl_skeletal.integer && !r_showsurfaces.integer;
5504         case RENDERPATH_GLES2:
5505                 if(!vid_gammatables_trivial)
5506                 {
5507                         if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5508                         {
5509                                 // build GLSL gamma texture
5510 #define RAMPWIDTH 256
5511                                 unsigned short ramp[RAMPWIDTH * 3];
5512                                 unsigned char rampbgr[RAMPWIDTH][4];
5513                                 int i;
5514
5515                                 r_texture_gammaramps_serial = vid_gammatables_serial;
5516
5517                                 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5518                                 for(i = 0; i < RAMPWIDTH; ++i)
5519                                 {
5520                                         rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5521                                         rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5522                                         rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5523                                         rampbgr[i][3] = 0;
5524                                 }
5525                                 if (r_texture_gammaramps)
5526                                 {
5527                                         R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1);
5528                                 }
5529                                 else
5530                                 {
5531                                         r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5532                                 }
5533                         }
5534                 }
5535                 else
5536                 {
5537                         // remove GLSL gamma texture
5538                 }
5539                 break;
5540         }
5541 }
5542
5543 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5544 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5545 /*
5546 ================
5547 R_SelectScene
5548 ================
5549 */
5550 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5551         if( scenetype != r_currentscenetype ) {
5552                 // store the old scenetype
5553                 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5554                 r_currentscenetype = scenetype;
5555                 // move in the new scene
5556                 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5557         }
5558 }
5559
5560 /*
5561 ================
5562 R_GetScenePointer
5563 ================
5564 */
5565 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5566 {
5567         // of course, we could also add a qboolean that provides a lock state and a ReleaseScenePointer function..
5568         if( scenetype == r_currentscenetype ) {
5569                 return &r_refdef.scene;
5570         } else {
5571                 return &r_scenes_store[ scenetype ];
5572         }
5573 }
5574
5575 static int R_SortEntities_Compare(const void *ap, const void *bp)
5576 {
5577         const entity_render_t *a = *(const entity_render_t **)ap;
5578         const entity_render_t *b = *(const entity_render_t **)bp;
5579
5580         // 1. compare model
5581         if(a->model < b->model)
5582                 return -1;
5583         if(a->model > b->model)
5584                 return +1;
5585
5586         // 2. compare skin
5587         // TODO possibly calculate the REAL skinnum here first using
5588         // skinscenes?
5589         if(a->skinnum < b->skinnum)
5590                 return -1;
5591         if(a->skinnum > b->skinnum)
5592                 return +1;
5593
5594         // everything we compared is equal
5595         return 0;
5596 }
5597 static void R_SortEntities(void)
5598 {
5599         // below or equal 2 ents, sorting never gains anything
5600         if(r_refdef.scene.numentities <= 2)
5601                 return;
5602         // sort
5603         qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5604 }
5605
5606 /*
5607 ================
5608 R_RenderView
5609 ================
5610 */
5611 extern cvar_t r_shadow_bouncegrid;
5612 extern cvar_t v_isometric;
5613 extern void V_MakeViewIsometric(void);
5614 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5615 {
5616         matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5617         int viewfbo = 0;
5618         rtexture_t *viewdepthtexture = NULL;
5619         rtexture_t *viewcolortexture = NULL;
5620         int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5621
5622         // finish any 2D rendering that was queued
5623         DrawQ_Finish();
5624
5625         if (r_timereport_active)
5626                 R_TimeReport("start");
5627         r_textureframe++; // used only by R_GetCurrentTexture
5628         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5629
5630         if(R_CompileShader_CheckStaticParms())
5631                 R_GLSL_Restart_f(&cmd_client);
5632
5633         if (!r_drawentities.integer)
5634                 r_refdef.scene.numentities = 0;
5635         else if (r_sortentities.integer)
5636                 R_SortEntities();
5637
5638         R_AnimCache_ClearCache();
5639
5640         /* adjust for stereo display */
5641         if(R_Stereo_Active())
5642         {
5643                 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);
5644                 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5645         }
5646
5647         if (r_refdef.view.isoverlay)
5648         {
5649                 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5650                 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5651                 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5652                 R_TimeReport("depthclear");
5653
5654                 r_refdef.view.showdebug = false;
5655
5656                 r_fb.water.enabled = false;
5657                 r_fb.water.numwaterplanes = 0;
5658
5659                 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5660
5661                 r_refdef.view.matrix = originalmatrix;
5662
5663                 CHECKGLERROR
5664                 return;
5665         }
5666
5667         if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5668         {
5669                 r_refdef.view.matrix = originalmatrix;
5670                 return;
5671         }
5672
5673         r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5674         if (v_isometric.integer && r_refdef.view.ismain)
5675                 V_MakeViewIsometric();
5676
5677         r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5678
5679         if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5680                 // in sRGB fallback, behave similar to true sRGB: convert this
5681                 // value from linear to sRGB
5682                 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5683
5684         R_RenderView_UpdateViewVectors();
5685
5686         R_Shadow_UpdateWorldLightSelection();
5687
5688         // this will set up r_fb.rt_screen
5689         R_Bloom_StartFrame();
5690
5691         // apply bloom brightness offset
5692         if(r_fb.rt_bloom)
5693                 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5694
5695         // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5696         if (r_fb.rt_screen)
5697         {
5698                 viewfbo = r_fb.rt_screen->fbo;
5699                 viewdepthtexture = r_fb.rt_screen->depthtexture;
5700                 viewcolortexture = r_fb.rt_screen->colortexture[0];
5701                 viewx = 0;
5702                 viewy = 0;
5703                 viewwidth = width;
5704                 viewheight = height;
5705         }
5706
5707         R_Water_StartFrame();
5708
5709         CHECKGLERROR
5710         if (r_timereport_active)
5711                 R_TimeReport("viewsetup");
5712
5713         R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5714
5715         // clear the whole fbo every frame - otherwise the driver will consider
5716         // it to be an inter-frame texture and stall in multi-gpu configurations
5717         if (r_fb.rt_screen)
5718                 GL_ScissorTest(false);
5719         R_ClearScreen(r_refdef.fogenabled);
5720         if (r_timereport_active)
5721                 R_TimeReport("viewclear");
5722
5723         r_refdef.view.clear = true;
5724
5725         r_refdef.view.showdebug = true;
5726
5727         R_View_Update();
5728         if (r_timereport_active)
5729                 R_TimeReport("visibility");
5730
5731         R_AnimCache_CacheVisibleEntities();
5732         if (r_timereport_active)
5733                 R_TimeReport("animcache");
5734
5735         R_Shadow_UpdateBounceGridTexture();
5736         // R_Shadow_UpdateBounceGridTexture called R_TimeReport a few times internally, so we don't need to do that here.
5737
5738         r_fb.water.numwaterplanes = 0;
5739         if (r_fb.water.enabled)
5740                 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5741
5742         // for the actual view render we use scissoring a fair amount, so scissor
5743         // test needs to be on
5744         if (r_fb.rt_screen)
5745                 GL_ScissorTest(true);
5746         GL_Scissor(viewx, viewy, viewwidth, viewheight);
5747         R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5748         r_fb.water.numwaterplanes = 0;
5749
5750         // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5751         GL_ScissorTest(false);
5752
5753         R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
5754         if (r_timereport_active)
5755                 R_TimeReport("blendview");
5756
5757         r_refdef.view.matrix = originalmatrix;
5758
5759         CHECKGLERROR
5760
5761         // go back to 2d rendering
5762         DrawQ_Start();
5763 }
5764
5765 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5766 {
5767         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5768         {
5769                 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5770                 if (r_timereport_active)
5771                         R_TimeReport("waterworld");
5772         }
5773
5774         // don't let sound skip if going slow
5775         if (r_refdef.scene.extraupdate)
5776                 S_ExtraUpdate ();
5777
5778         R_DrawModelsAddWaterPlanes();
5779         if (r_timereport_active)
5780                 R_TimeReport("watermodels");
5781
5782         if (r_fb.water.numwaterplanes)
5783         {
5784                 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5785                 if (r_timereport_active)
5786                         R_TimeReport("waterscenes");
5787         }
5788 }
5789
5790 extern cvar_t cl_locs_show;
5791 static void R_DrawLocs(void);
5792 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5793 static void R_DrawModelDecals(void);
5794 extern qboolean r_shadow_usingdeferredprepass;
5795 extern int r_shadow_shadowmapatlas_modelshadows_size;
5796 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5797 {
5798         qboolean shadowmapping = false;
5799
5800         if (r_timereport_active)
5801                 R_TimeReport("beginscene");
5802
5803         r_refdef.stats[r_stat_renders]++;
5804
5805         R_UpdateFog();
5806
5807         // don't let sound skip if going slow
5808         if (r_refdef.scene.extraupdate)
5809                 S_ExtraUpdate ();
5810
5811         R_MeshQueue_BeginScene();
5812
5813         R_SkyStartFrame();
5814
5815         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);
5816
5817         if (r_timereport_active)
5818                 R_TimeReport("skystartframe");
5819
5820         if (cl.csqc_vidvars.drawworld)
5821         {
5822                 // don't let sound skip if going slow
5823                 if (r_refdef.scene.extraupdate)
5824                         S_ExtraUpdate ();
5825
5826                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5827                 {
5828                         r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5829                         if (r_timereport_active)
5830                                 R_TimeReport("worldsky");
5831                 }
5832
5833                 if (R_DrawBrushModelsSky() && r_timereport_active)
5834                         R_TimeReport("bmodelsky");
5835
5836                 if (skyrendermasked && skyrenderlater)
5837                 {
5838                         // we have to force off the water clipping plane while rendering sky
5839                         R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5840                         R_Sky();
5841                         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5842                         if (r_timereport_active)
5843                                 R_TimeReport("sky");
5844                 }
5845         }
5846
5847         // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5848         r_shadow_viewfbo = viewfbo;
5849         r_shadow_viewdepthtexture = viewdepthtexture;
5850         r_shadow_viewcolortexture = viewcolortexture;
5851         r_shadow_viewx = viewx;
5852         r_shadow_viewy = viewy;
5853         r_shadow_viewwidth = viewwidth;
5854         r_shadow_viewheight = viewheight;
5855
5856         R_Shadow_PrepareModelShadows();
5857         R_Shadow_PrepareLights();
5858         if (r_timereport_active)
5859                 R_TimeReport("preparelights");
5860
5861         // render all the shadowmaps that will be used for this view
5862         shadowmapping = R_Shadow_ShadowMappingEnabled();
5863         if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
5864         {
5865                 R_Shadow_DrawShadowMaps();
5866                 if (r_timereport_active)
5867                         R_TimeReport("shadowmaps");
5868         }
5869
5870         // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
5871         if (r_shadow_usingdeferredprepass)
5872                 R_Shadow_DrawPrepass();
5873
5874         // now we begin the forward pass of the view render
5875         if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
5876         {
5877                 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
5878                 if (r_timereport_active)
5879                         R_TimeReport("worlddepth");
5880         }
5881         if (r_depthfirst.integer >= 2)
5882         {
5883                 R_DrawModelsDepth();
5884                 if (r_timereport_active)
5885                         R_TimeReport("modeldepth");
5886         }
5887
5888         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
5889         {
5890                 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
5891                 if (r_timereport_active)
5892                         R_TimeReport("world");
5893         }
5894
5895         // don't let sound skip if going slow
5896         if (r_refdef.scene.extraupdate)
5897                 S_ExtraUpdate ();
5898
5899         R_DrawModels();
5900         if (r_timereport_active)
5901                 R_TimeReport("models");
5902
5903         // don't let sound skip if going slow
5904         if (r_refdef.scene.extraupdate)
5905                 S_ExtraUpdate ();
5906
5907         if (!r_shadow_usingdeferredprepass)
5908         {
5909                 R_Shadow_DrawLights();
5910                 if (r_timereport_active)
5911                         R_TimeReport("rtlights");
5912         }
5913
5914         // don't let sound skip if going slow
5915         if (r_refdef.scene.extraupdate)
5916                 S_ExtraUpdate ();
5917
5918         if (cl.csqc_vidvars.drawworld)
5919         {
5920                 R_DrawModelDecals();
5921                 if (r_timereport_active)
5922                         R_TimeReport("modeldecals");
5923
5924                 R_DrawParticles();
5925                 if (r_timereport_active)
5926                         R_TimeReport("particles");
5927
5928                 R_DrawExplosions();
5929                 if (r_timereport_active)
5930                         R_TimeReport("explosions");
5931         }
5932
5933         if (r_refdef.view.showdebug)
5934         {
5935                 if (cl_locs_show.integer)
5936                 {
5937                         R_DrawLocs();
5938                         if (r_timereport_active)
5939                                 R_TimeReport("showlocs");
5940                 }
5941
5942                 if (r_drawportals.integer)
5943                 {
5944                         R_DrawPortals();
5945                         if (r_timereport_active)
5946                                 R_TimeReport("portals");
5947                 }
5948
5949                 if (r_showbboxes_client.value > 0)
5950                 {
5951                         R_DrawEntityBBoxes(CLVM_prog);
5952                         if (r_timereport_active)
5953                                 R_TimeReport("clbboxes");
5954                 }
5955                 if (r_showbboxes.value > 0)
5956                 {
5957                         R_DrawEntityBBoxes(SVVM_prog);
5958                         if (r_timereport_active)
5959                                 R_TimeReport("svbboxes");
5960                 }
5961         }
5962
5963         if (r_transparent.integer)
5964         {
5965                 R_MeshQueue_RenderTransparent();
5966                 if (r_timereport_active)
5967                         R_TimeReport("drawtrans");
5968         }
5969
5970         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))
5971         {
5972                 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
5973                 if (r_timereport_active)
5974                         R_TimeReport("worlddebug");
5975                 R_DrawModelsDebug();
5976                 if (r_timereport_active)
5977                         R_TimeReport("modeldebug");
5978         }
5979
5980         if (cl.csqc_vidvars.drawworld)
5981         {
5982                 R_Shadow_DrawCoronas();
5983                 if (r_timereport_active)
5984                         R_TimeReport("coronas");
5985         }
5986
5987         // don't let sound skip if going slow
5988         if (r_refdef.scene.extraupdate)
5989                 S_ExtraUpdate ();
5990 }
5991
5992 static const unsigned short bboxelements[36] =
5993 {
5994         5, 1, 3, 5, 3, 7,
5995         6, 2, 0, 6, 0, 4,
5996         7, 3, 2, 7, 2, 6,
5997         4, 0, 1, 4, 1, 5,
5998         4, 5, 7, 4, 7, 6,
5999         1, 0, 2, 1, 2, 3,
6000 };
6001
6002 #define BBOXEDGES 13
6003 static const float bboxedges[BBOXEDGES][6] = 
6004 {
6005         // whole box
6006         { 0, 0, 0, 1, 1, 1 },
6007         // bottom edges
6008         { 0, 0, 0, 0, 1, 0 },
6009         { 0, 0, 0, 1, 0, 0 },
6010         { 0, 1, 0, 1, 1, 0 },
6011         { 1, 0, 0, 1, 1, 0 },
6012         // top edges
6013         { 0, 0, 1, 0, 1, 1 },
6014         { 0, 0, 1, 1, 0, 1 },
6015         { 0, 1, 1, 1, 1, 1 },
6016         { 1, 0, 1, 1, 1, 1 },
6017         // vertical edges
6018         { 0, 0, 0, 0, 0, 1 },
6019         { 1, 0, 0, 1, 0, 1 },
6020         { 0, 1, 0, 0, 1, 1 },
6021         { 1, 1, 0, 1, 1, 1 },
6022 };
6023
6024 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6025 {
6026         int numvertices = BBOXEDGES * 8;
6027         float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6028         int numtriangles = BBOXEDGES * 12;
6029         unsigned short elements[BBOXEDGES * 36];
6030         int i, edge;
6031         float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6032
6033         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6034
6035         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6036         GL_DepthMask(false);
6037         GL_DepthRange(0, 1);
6038         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6039
6040         for (edge = 0; edge < BBOXEDGES; edge++)
6041         {
6042                 for (i = 0; i < 3; i++)
6043                 {
6044                         edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6045                         edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6046                 }
6047                 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6048                 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6049                 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6050                 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6051                 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6052                 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6053                 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6054                 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6055                 for (i = 0; i < 36; i++)
6056                         elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6057         }
6058         R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6059         if (r_refdef.fogenabled)
6060         {
6061                 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6062                 {
6063                         f1 = RSurf_FogVertex(v);
6064                         f2 = 1 - f1;
6065                         c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6066                         c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6067                         c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6068                 }
6069         }
6070         R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6071         R_Mesh_ResetTextureState();
6072         R_SetupShader_Generic_NoTexture(false, false);
6073         R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6074 }
6075
6076 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6077 {
6078         // hacky overloading of the parameters
6079         prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6080         int i;
6081         float color[4];
6082         prvm_edict_t *edict;
6083
6084         GL_CullFace(GL_NONE);
6085         R_SetupShader_Generic_NoTexture(false, false);
6086
6087         for (i = 0;i < numsurfaces;i++)
6088         {
6089                 edict = PRVM_EDICT_NUM(surfacelist[i]);
6090                 switch ((int)PRVM_serveredictfloat(edict, solid))
6091                 {
6092                         case SOLID_NOT:      Vector4Set(color, 1, 1, 1, 0.05);break;
6093                         case SOLID_TRIGGER:  Vector4Set(color, 1, 0, 1, 0.10);break;
6094                         case SOLID_BBOX:     Vector4Set(color, 0, 1, 0, 0.10);break;
6095                         case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6096                         case SOLID_BSP:      Vector4Set(color, 0, 0, 1, 0.05);break;
6097                         case SOLID_CORPSE:   Vector4Set(color, 1, 0.5, 0, 0.05);break;
6098                         default:             Vector4Set(color, 0, 0, 0, 0.50);break;
6099                 }
6100                 if (prog == CLVM_prog)
6101                         color[3] *= r_showbboxes_client.value;
6102                 else
6103                         color[3] *= r_showbboxes.value;
6104                 color[3] = bound(0, color[3], 1);
6105                 GL_DepthTest(!r_showdisabledepthtest.integer);
6106                 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6107         }
6108 }
6109
6110 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6111 {
6112         int i;
6113         prvm_edict_t *edict;
6114         vec3_t center;
6115
6116         if (prog == NULL)
6117                 return;
6118
6119         for (i = 0; i < prog->num_edicts; i++)
6120         {
6121                 edict = PRVM_EDICT_NUM(i);
6122                 if (edict->priv.server->free)
6123                         continue;
6124                 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6125                 if (PRVM_gameedictedict(edict, tag_entity) != 0)
6126                         continue;
6127                 if (prog == SVVM_prog && PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6128                         continue;
6129                 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6130                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6131         }
6132 }
6133
6134 static const int nomodelelement3i[24] =
6135 {
6136         5, 2, 0,
6137         5, 1, 2,
6138         5, 0, 3,
6139         5, 3, 1,
6140         0, 2, 4,
6141         2, 1, 4,
6142         3, 0, 4,
6143         1, 3, 4
6144 };
6145
6146 static const unsigned short nomodelelement3s[24] =
6147 {
6148         5, 2, 0,
6149         5, 1, 2,
6150         5, 0, 3,
6151         5, 3, 1,
6152         0, 2, 4,
6153         2, 1, 4,
6154         3, 0, 4,
6155         1, 3, 4
6156 };
6157
6158 static const float nomodelvertex3f[6*3] =
6159 {
6160         -16,   0,   0,
6161          16,   0,   0,
6162           0, -16,   0,
6163           0,  16,   0,
6164           0,   0, -16,
6165           0,   0,  16
6166 };
6167
6168 static const float nomodelcolor4f[6*4] =
6169 {
6170         0.0f, 0.0f, 0.5f, 1.0f,
6171         0.0f, 0.0f, 0.5f, 1.0f,
6172         0.0f, 0.5f, 0.0f, 1.0f,
6173         0.0f, 0.5f, 0.0f, 1.0f,
6174         0.5f, 0.0f, 0.0f, 1.0f,
6175         0.5f, 0.0f, 0.0f, 1.0f
6176 };
6177
6178 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6179 {
6180         int i;
6181         float f1, f2, *c;
6182         float color4f[6*4];
6183
6184         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);
6185
6186         // this is only called once per entity so numsurfaces is always 1, and
6187         // surfacelist is always {0}, so this code does not handle batches
6188
6189         if (rsurface.ent_flags & RENDER_ADDITIVE)
6190         {
6191                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6192                 GL_DepthMask(false);
6193         }
6194         else if (ent->alpha < 1)
6195         {
6196                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6197                 GL_DepthMask(false);
6198         }
6199         else
6200         {
6201                 GL_BlendFunc(GL_ONE, GL_ZERO);
6202                 GL_DepthMask(true);
6203         }
6204         GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6205         GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6206         GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6207         GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6208         memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6209         for (i = 0, c = color4f;i < 6;i++, c += 4)
6210         {
6211                 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6212                 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6213                 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6214                 c[3] *= ent->alpha;
6215         }
6216         if (r_refdef.fogenabled)
6217         {
6218                 for (i = 0, c = color4f;i < 6;i++, c += 4)
6219                 {
6220                         f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6221                         f2 = 1 - f1;
6222                         c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6223                         c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6224                         c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6225                 }
6226         }
6227 //      R_Mesh_ResetTextureState();
6228         R_SetupShader_Generic_NoTexture(false, false);
6229         R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6230         R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6231 }
6232
6233 void R_DrawNoModel(entity_render_t *ent)
6234 {
6235         vec3_t org;
6236         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6237         if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6238                 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6239         else
6240                 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6241 }
6242
6243 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6244 {
6245         vec3_t right1, right2, diff, normal;
6246
6247         VectorSubtract (org2, org1, normal);
6248
6249         // calculate 'right' vector for start
6250         VectorSubtract (r_refdef.view.origin, org1, diff);
6251         CrossProduct (normal, diff, right1);
6252         VectorNormalize (right1);
6253
6254         // calculate 'right' vector for end
6255         VectorSubtract (r_refdef.view.origin, org2, diff);
6256         CrossProduct (normal, diff, right2);
6257         VectorNormalize (right2);
6258
6259         vert[ 0] = org1[0] + width * right1[0];
6260         vert[ 1] = org1[1] + width * right1[1];
6261         vert[ 2] = org1[2] + width * right1[2];
6262         vert[ 3] = org1[0] - width * right1[0];
6263         vert[ 4] = org1[1] - width * right1[1];
6264         vert[ 5] = org1[2] - width * right1[2];
6265         vert[ 6] = org2[0] - width * right2[0];
6266         vert[ 7] = org2[1] - width * right2[1];
6267         vert[ 8] = org2[2] - width * right2[2];
6268         vert[ 9] = org2[0] + width * right2[0];
6269         vert[10] = org2[1] + width * right2[1];
6270         vert[11] = org2[2] + width * right2[2];
6271 }
6272
6273 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)
6274 {
6275         vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6276         vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6277         vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6278         vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6279         vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6280         vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6281         vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6282         vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6283         vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6284         vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6285         vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6286         vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6287 }
6288
6289 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6290 {
6291         int i;
6292         float *vertex3f;
6293         float v[3];
6294         VectorSet(v, x, y, z);
6295         for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6296                 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6297                         break;
6298         if (i == mesh->numvertices)
6299         {
6300                 if (mesh->numvertices < mesh->maxvertices)
6301                 {
6302                         VectorCopy(v, vertex3f);
6303                         mesh->numvertices++;
6304                 }
6305                 return mesh->numvertices;
6306         }
6307         else
6308                 return i;
6309 }
6310
6311 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6312 {
6313         int i;
6314         int *e, element[3];
6315         element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6316         element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6317         e = mesh->element3i + mesh->numtriangles * 3;
6318         for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6319         {
6320                 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6321                 if (mesh->numtriangles < mesh->maxtriangles)
6322                 {
6323                         *e++ = element[0];
6324                         *e++ = element[1];
6325                         *e++ = element[2];
6326                         mesh->numtriangles++;
6327                 }
6328                 element[1] = element[2];
6329         }
6330 }
6331
6332 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6333 {
6334         int i;
6335         int *e, element[3];
6336         element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6337         element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6338         e = mesh->element3i + mesh->numtriangles * 3;
6339         for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6340         {
6341                 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6342                 if (mesh->numtriangles < mesh->maxtriangles)
6343                 {
6344                         *e++ = element[0];
6345                         *e++ = element[1];
6346                         *e++ = element[2];
6347                         mesh->numtriangles++;
6348                 }
6349                 element[1] = element[2];
6350         }
6351 }
6352
6353 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6354 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6355 {
6356         int planenum, planenum2;
6357         int w;
6358         int tempnumpoints;
6359         mplane_t *plane, *plane2;
6360         double maxdist;
6361         double temppoints[2][256*3];
6362         // figure out how large a bounding box we need to properly compute this brush
6363         maxdist = 0;
6364         for (w = 0;w < numplanes;w++)
6365                 maxdist = max(maxdist, fabs(planes[w].dist));
6366         // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6367         maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6368         for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6369         {
6370                 w = 0;
6371                 tempnumpoints = 4;
6372                 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6373                 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6374                 {
6375                         if (planenum2 == planenum)
6376                                 continue;
6377                         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);
6378                         w = !w;
6379                 }
6380                 if (tempnumpoints < 3)
6381                         continue;
6382                 // generate elements forming a triangle fan for this polygon
6383                 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6384         }
6385 }
6386
6387 static qboolean R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6388 {
6389         if(parms[0] == 0 && parms[1] == 0)
6390                 return false;
6391         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6392                 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6393                         return false;
6394         return true;
6395 }
6396
6397 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6398 {
6399         double index, f;
6400         index = parms[2] + rsurface.shadertime * parms[3];
6401         index -= floor(index);
6402         switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6403         {
6404         default:
6405         case Q3WAVEFUNC_NONE:
6406         case Q3WAVEFUNC_NOISE:
6407         case Q3WAVEFUNC_COUNT:
6408                 f = 0;
6409                 break;
6410         case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6411         case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6412         case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6413         case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6414         case Q3WAVEFUNC_TRIANGLE:
6415                 index *= 4;
6416                 f = index - floor(index);
6417                 if (index < 1)
6418                 {
6419                         // f = f;
6420                 }
6421                 else if (index < 2)
6422                         f = 1 - f;
6423                 else if (index < 3)
6424                         f = -f;
6425                 else
6426                         f = -(1 - f);
6427                 break;
6428         }
6429         f = parms[0] + parms[1] * f;
6430         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6431                 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6432         return (float) f;
6433 }
6434
6435 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6436 {
6437         int w, h, idx;
6438         float shadertime;
6439         float f;
6440         float offsetd[2];
6441         float tcmat[12];
6442         matrix4x4_t matrix, temp;
6443         // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6444         // it's better to have one huge fixup every 9 hours than gradual
6445         // degradation over time which looks consistently bad after many hours.
6446         //
6447         // tcmod scroll in particular suffers from this degradation which can't be
6448         // effectively worked around even with floor() tricks because we don't
6449         // know if tcmod scroll is the last tcmod being applied, and for clampmap
6450         // a workaround involving floor() would be incorrect anyway...
6451         shadertime = rsurface.shadertime;
6452         if (shadertime >= 32768.0f)
6453                 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6454         switch(tcmod->tcmod)
6455         {
6456                 case Q3TCMOD_COUNT:
6457                 case Q3TCMOD_NONE:
6458                         if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6459                                 matrix = r_waterscrollmatrix;
6460                         else
6461                                 matrix = identitymatrix;
6462                         break;
6463                 case Q3TCMOD_ENTITYTRANSLATE:
6464                         // this is used in Q3 to allow the gamecode to control texcoord
6465                         // scrolling on the entity, which is not supported in darkplaces yet.
6466                         Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6467                         break;
6468                 case Q3TCMOD_ROTATE:
6469                         Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6470                         Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6471                         Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6472                         break;
6473                 case Q3TCMOD_SCALE:
6474                         Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6475                         break;
6476                 case Q3TCMOD_SCROLL:
6477                         // this particular tcmod is a "bug for bug" compatible one with regards to
6478                         // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6479                         // specifically did the wrapping and so we must mimic that...
6480                         offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6481                         offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6482                         Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6483                         break;
6484                 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6485                         w = (int) tcmod->parms[0];
6486                         h = (int) tcmod->parms[1];
6487                         f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6488                         f = f - floor(f);
6489                         idx = (int) floor(f * w * h);
6490                         Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6491                         break;
6492                 case Q3TCMOD_STRETCH:
6493                         f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6494                         Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6495                         break;
6496                 case Q3TCMOD_TRANSFORM:
6497                         VectorSet(tcmat +  0, tcmod->parms[0], tcmod->parms[1], 0);
6498                         VectorSet(tcmat +  3, tcmod->parms[2], tcmod->parms[3], 0);
6499                         VectorSet(tcmat +  6, 0                   , 0                , 1);
6500                         VectorSet(tcmat +  9, tcmod->parms[4], tcmod->parms[5], 0);
6501                         Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6502                         break;
6503                 case Q3TCMOD_TURBULENT:
6504                         // this is handled in the RSurf_PrepareVertices function
6505                         matrix = identitymatrix;
6506                         break;
6507         }
6508         temp = *texmatrix;
6509         Matrix4x4_Concat(texmatrix, &matrix, &temp);
6510 }
6511
6512 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6513 {
6514         int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6515         char name[MAX_QPATH];
6516         skinframe_t *skinframe;
6517         unsigned char pixels[296*194];
6518         strlcpy(cache->name, skinname, sizeof(cache->name));
6519         dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6520         if (developer_loading.integer)
6521                 Con_Printf("loading %s\n", name);
6522         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6523         if (!skinframe || !skinframe->base)
6524         {
6525                 unsigned char *f;
6526                 fs_offset_t filesize;
6527                 skinframe = NULL;
6528                 f = FS_LoadFile(name, tempmempool, true, &filesize);
6529                 if (f)
6530                 {
6531                         if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6532                                 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6533                         Mem_Free(f);
6534                 }
6535         }
6536         cache->skinframe = skinframe;
6537 }
6538
6539 texture_t *R_GetCurrentTexture(texture_t *t)
6540 {
6541         int i, q;
6542         const entity_render_t *ent = rsurface.entity;
6543         dp_model_t *model = ent->model; // when calling this, ent must not be NULL
6544         q3shaderinfo_layer_tcmod_t *tcmod;
6545         float specularscale = 0.0f;
6546
6547         if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6548                 return t->currentframe;
6549         t->update_lastrenderframe = r_textureframe;
6550         t->update_lastrenderentity = (void *)ent;
6551
6552         if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6553                 t->camera_entity = ent->entitynumber;
6554         else
6555                 t->camera_entity = 0;
6556
6557         // switch to an alternate material if this is a q1bsp animated material
6558         {
6559                 texture_t *texture = t;
6560                 int s = rsurface.ent_skinnum;
6561                 if ((unsigned int)s >= (unsigned int)model->numskins)
6562                         s = 0;
6563                 if (model->skinscenes)
6564                 {
6565                         if (model->skinscenes[s].framecount > 1)
6566                                 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6567                         else
6568                                 s = model->skinscenes[s].firstframe;
6569                 }
6570                 if (s > 0)
6571                         t = t + s * model->num_surfaces;
6572                 if (t->animated)
6573                 {
6574                         // use an alternate animation if the entity's frame is not 0,
6575                         // and only if the texture has an alternate animation
6576                         if (t->animated == 2) // q2bsp
6577                                 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6578                         else if (rsurface.ent_alttextures && t->anim_total[1])
6579                                 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6580                         else
6581                                 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6582                 }
6583                 texture->currentframe = t;
6584         }
6585
6586         // update currentskinframe to be a qw skin or animation frame
6587         if (rsurface.ent_qwskin >= 0)
6588         {
6589                 i = rsurface.ent_qwskin;
6590                 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6591                 {
6592                         r_qwskincache_size = cl.maxclients;
6593                         if (r_qwskincache)
6594                                 Mem_Free(r_qwskincache);
6595                         r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6596                 }
6597                 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6598                         R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6599                 t->currentskinframe = r_qwskincache[i].skinframe;
6600                 if (t->materialshaderpass && t->currentskinframe == NULL)
6601                         t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6602         }
6603         else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6604                 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6605         if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6606                 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6607
6608         t->currentmaterialflags = t->basematerialflags;
6609         t->currentalpha = rsurface.entity->alpha * t->basealpha;
6610         if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_water.integer || r_novis.integer || r_trippy.integer))
6611                 t->currentalpha *= r_wateralpha.value;
6612         if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6613                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6614         if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6615                 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6616
6617         // decide on which type of lighting to use for this surface
6618         if (rsurface.entity->render_modellight_forced)
6619                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6620         if (rsurface.entity->render_rtlight_disabled)
6621                 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6622         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6623         {
6624                 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6625                 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NORTLIGHT;
6626                 for (q = 0; q < 3; q++)
6627                 {
6628                         t->render_glowmod[q] = rsurface.entity->glowmod[q];
6629                         t->render_modellight_lightdir[q] = q == 2;
6630                         t->render_modellight_ambient[q] = 1;
6631                         t->render_modellight_diffuse[q] = 0;
6632                         t->render_modellight_specular[q] = 0;
6633                         t->render_lightmap_ambient[q] = 0;
6634                         t->render_lightmap_diffuse[q] = 0;
6635                         t->render_lightmap_specular[q] = 0;
6636                         t->render_rtlight_diffuse[q] = 0;
6637                         t->render_rtlight_specular[q] = 0;
6638                 }
6639         }
6640         else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6641         {
6642                 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6643                 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT;
6644                 for (q = 0; q < 3; q++)
6645                 {
6646                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6647                         t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6648                         t->render_modellight_lightdir[q] = q == 2;
6649                         t->render_modellight_diffuse[q] = 0;
6650                         t->render_modellight_specular[q] = 0;
6651                         t->render_lightmap_ambient[q] = 0;
6652                         t->render_lightmap_diffuse[q] = 0;
6653                         t->render_lightmap_specular[q] = 0;
6654                         t->render_rtlight_diffuse[q] = 0;
6655                         t->render_rtlight_specular[q] = 0;
6656                 }
6657         }
6658         else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6659         {
6660                 // ambient + single direction light (modellight)
6661                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6662                 for (q = 0; q < 3; q++)
6663                 {
6664                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6665                         t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6666                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6667                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6668                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6669                         t->render_lightmap_ambient[q] = 0;
6670                         t->render_lightmap_diffuse[q] = 0;
6671                         t->render_lightmap_specular[q] = 0;
6672                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6673                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6674                 }
6675         }
6676         else
6677         {
6678                 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6679                 for (q = 0; q < 3; q++)
6680                 {
6681                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6682                         t->render_modellight_lightdir[q] = q == 2;
6683                         t->render_modellight_ambient[q] = 0;
6684                         t->render_modellight_diffuse[q] = 0;
6685                         t->render_modellight_specular[q] = 0;
6686                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6687                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6688                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6689                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6690                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6691                 }
6692         }
6693
6694         if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6695         {
6696                 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6697                 // attribute, we punt it to the lightmap path and hope for the best,
6698                 // but lighting doesn't work.
6699                 //
6700                 // FIXME: this is fine for effects but CSQC polygons should be subject
6701                 // to lighting.
6702                 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6703                 for (q = 0; q < 3; q++)
6704                 {
6705                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6706                         t->render_modellight_lightdir[q] = q == 2;
6707                         t->render_modellight_ambient[q] = 0;
6708                         t->render_modellight_diffuse[q] = 0;
6709                         t->render_modellight_specular[q] = 0;
6710                         t->render_lightmap_ambient[q] = 0;
6711                         t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6712                         t->render_lightmap_specular[q] = 0;
6713                         t->render_rtlight_diffuse[q] = 0;
6714                         t->render_rtlight_specular[q] = 0;
6715                 }
6716         }
6717
6718         for (q = 0; q < 3; q++)
6719         {
6720                 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6721                 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6722         }
6723
6724         if (rsurface.ent_flags & RENDER_ADDITIVE)
6725                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6726         else if (t->currentalpha < 1)
6727                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6728         // LadyHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6729         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6730                 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6731         if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6732                 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6733         if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6734                 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6735         if (t->backgroundshaderpass)
6736                 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6737         if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6738         {
6739                 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6740                         t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6741         }
6742         else
6743                 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6744         if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6745         {
6746                 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6747                 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6748         }
6749         if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6750                 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6751
6752         // there is no tcmod
6753         if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6754         {
6755                 t->currenttexmatrix = r_waterscrollmatrix;
6756                 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6757         }
6758         else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6759         {
6760                 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6761                 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6762         }
6763
6764         if (t->materialshaderpass)
6765                 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6766                         R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6767
6768         t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6769         if (t->currentskinframe->qpixels)
6770                 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6771         t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6772         if (!t->basetexture)
6773                 t->basetexture = r_texture_notexture;
6774         t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6775         t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6776         t->nmaptexture = t->currentskinframe->nmap;
6777         if (!t->nmaptexture)
6778                 t->nmaptexture = r_texture_blanknormalmap;
6779         t->glosstexture = r_texture_black;
6780         t->glowtexture = t->currentskinframe->glow;
6781         t->fogtexture = t->currentskinframe->fog;
6782         t->reflectmasktexture = t->currentskinframe->reflect;
6783         if (t->backgroundshaderpass)
6784         {
6785                 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6786                         R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6787                 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6788                 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6789                 t->backgroundglosstexture = r_texture_black;
6790                 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6791                 if (!t->backgroundnmaptexture)
6792                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6793                 // make sure that if glow is going to be used, both textures are not NULL
6794                 if (!t->backgroundglowtexture && t->glowtexture)
6795                         t->backgroundglowtexture = r_texture_black;
6796                 if (!t->glowtexture && t->backgroundglowtexture)
6797                         t->glowtexture = r_texture_black;
6798         }
6799         else
6800         {
6801                 t->backgroundbasetexture = r_texture_white;
6802                 t->backgroundnmaptexture = r_texture_blanknormalmap;
6803                 t->backgroundglosstexture = r_texture_black;
6804                 t->backgroundglowtexture = NULL;
6805         }
6806         t->specularpower = r_shadow_glossexponent.value;
6807         // TODO: store reference values for these in the texture?
6808         if (r_shadow_gloss.integer > 0)
6809         {
6810                 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
6811                 {
6812                         if (r_shadow_glossintensity.value > 0)
6813                         {
6814                                 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
6815                                 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
6816                                 specularscale = r_shadow_glossintensity.value;
6817                         }
6818                 }
6819                 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
6820                 {
6821                         t->glosstexture = r_texture_white;
6822                         t->backgroundglosstexture = r_texture_white;
6823                         specularscale = r_shadow_gloss2intensity.value;
6824                         t->specularpower = r_shadow_gloss2exponent.value;
6825                 }
6826         }
6827         specularscale *= t->specularscalemod;
6828         t->specularpower *= t->specularpowermod;
6829
6830         // lightmaps mode looks bad with dlights using actual texturing, so turn
6831         // off the colormap and glossmap, but leave the normalmap on as it still
6832         // accurately represents the shading involved
6833         if (gl_lightmaps.integer)
6834         {
6835                 t->basetexture = r_texture_grey128;
6836                 t->pantstexture = r_texture_black;
6837                 t->shirttexture = r_texture_black;
6838                 if (gl_lightmaps.integer < 2)
6839                         t->nmaptexture = r_texture_blanknormalmap;
6840                 t->glosstexture = r_texture_black;
6841                 t->glowtexture = NULL;
6842                 t->fogtexture = NULL;
6843                 t->reflectmasktexture = NULL;
6844                 t->backgroundbasetexture = NULL;
6845                 if (gl_lightmaps.integer < 2)
6846                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6847                 t->backgroundglosstexture = r_texture_black;
6848                 t->backgroundglowtexture = NULL;
6849                 specularscale = 0;
6850                 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
6851         }
6852
6853         if (specularscale != 1.0f)
6854         {
6855                 for (q = 0; q < 3; q++)
6856                 {
6857                         t->render_modellight_specular[q] *= specularscale;
6858                         t->render_lightmap_specular[q] *= specularscale;
6859                         t->render_rtlight_specular[q] *= specularscale;
6860                 }
6861         }
6862
6863         t->currentblendfunc[0] = GL_ONE;
6864         t->currentblendfunc[1] = GL_ZERO;
6865         if (t->currentmaterialflags & MATERIALFLAG_ADD)
6866         {
6867                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6868                 t->currentblendfunc[1] = GL_ONE;
6869         }
6870         else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
6871         {
6872                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6873                 t->currentblendfunc[1] = GL_ONE_MINUS_SRC_ALPHA;
6874         }
6875         else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6876         {
6877                 t->currentblendfunc[0] = t->customblendfunc[0];
6878                 t->currentblendfunc[1] = t->customblendfunc[1];
6879         }
6880
6881         return t;
6882 }
6883
6884 rsurfacestate_t rsurface;
6885
6886 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
6887 {
6888         dp_model_t *model = ent->model;
6889         //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
6890         //      return;
6891         rsurface.entity = (entity_render_t *)ent;
6892         rsurface.skeleton = ent->skeleton;
6893         memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
6894         rsurface.ent_skinnum = ent->skinnum;
6895         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;
6896         rsurface.ent_flags = ent->flags;
6897         if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
6898                 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
6899         rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
6900         rsurface.matrix = ent->matrix;
6901         rsurface.inversematrix = ent->inversematrix;
6902         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
6903         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
6904         R_EntityMatrix(&rsurface.matrix);
6905         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
6906         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
6907         rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
6908         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
6909         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
6910         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
6911         memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
6912         rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
6913         rsurface.basepolygonfactor = r_refdef.polygonfactor;
6914         rsurface.basepolygonoffset = r_refdef.polygonoffset;
6915         if (ent->model->brush.submodel && !prepass)
6916         {
6917                 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
6918                 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
6919         }
6920         // if the animcache code decided it should use the shader path, skip the deform step
6921         rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
6922         rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
6923         rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
6924         rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
6925         rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
6926         if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
6927         {
6928                 if (ent->animcache_vertex3f)
6929                 {
6930                         r_refdef.stats[r_stat_batch_entitycache_count]++;
6931                         r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
6932                         r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
6933                         r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
6934                         rsurface.modelvertex3f = ent->animcache_vertex3f;
6935                         rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
6936                         rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
6937                         rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
6938                         rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
6939                         rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
6940                         rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
6941                         rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
6942                         rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
6943                         rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
6944                         rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
6945                         rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
6946                 }
6947                 else if (wanttangents)
6948                 {
6949                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
6950                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
6951                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
6952                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
6953                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6954                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6955                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6956                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6957                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
6958                         rsurface.modelvertex3f_vertexbuffer = NULL;
6959                         rsurface.modelvertex3f_bufferoffset = 0;
6960                         rsurface.modelvertex3f_vertexbuffer = 0;
6961                         rsurface.modelvertex3f_bufferoffset = 0;
6962                         rsurface.modelsvector3f_vertexbuffer = 0;
6963                         rsurface.modelsvector3f_bufferoffset = 0;
6964                         rsurface.modeltvector3f_vertexbuffer = 0;
6965                         rsurface.modeltvector3f_bufferoffset = 0;
6966                         rsurface.modelnormal3f_vertexbuffer = 0;
6967                         rsurface.modelnormal3f_bufferoffset = 0;
6968                 }
6969                 else if (wantnormals)
6970                 {
6971                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
6972                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
6973                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
6974                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
6975                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6976                         rsurface.modelsvector3f = NULL;
6977                         rsurface.modeltvector3f = NULL;
6978                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6979                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
6980                         rsurface.modelvertex3f_vertexbuffer = NULL;
6981                         rsurface.modelvertex3f_bufferoffset = 0;
6982                         rsurface.modelvertex3f_vertexbuffer = 0;
6983                         rsurface.modelvertex3f_bufferoffset = 0;
6984                         rsurface.modelsvector3f_vertexbuffer = 0;
6985                         rsurface.modelsvector3f_bufferoffset = 0;
6986                         rsurface.modeltvector3f_vertexbuffer = 0;
6987                         rsurface.modeltvector3f_bufferoffset = 0;
6988                         rsurface.modelnormal3f_vertexbuffer = 0;
6989                         rsurface.modelnormal3f_bufferoffset = 0;
6990                 }
6991                 else
6992                 {
6993                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
6994                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
6995                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
6996                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
6997                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6998                         rsurface.modelsvector3f = NULL;
6999                         rsurface.modeltvector3f = NULL;
7000                         rsurface.modelnormal3f = NULL;
7001                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7002                         rsurface.modelvertex3f_vertexbuffer = NULL;
7003                         rsurface.modelvertex3f_bufferoffset = 0;
7004                         rsurface.modelvertex3f_vertexbuffer = 0;
7005                         rsurface.modelvertex3f_bufferoffset = 0;
7006                         rsurface.modelsvector3f_vertexbuffer = 0;
7007                         rsurface.modelsvector3f_bufferoffset = 0;
7008                         rsurface.modeltvector3f_vertexbuffer = 0;
7009                         rsurface.modeltvector3f_bufferoffset = 0;
7010                         rsurface.modelnormal3f_vertexbuffer = 0;
7011                         rsurface.modelnormal3f_bufferoffset = 0;
7012                 }
7013                 rsurface.modelgeneratedvertex = true;
7014         }
7015         else
7016         {
7017                 if (rsurface.entityskeletaltransform3x4)
7018                 {
7019                         r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7020                         r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7021                         r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7022                         r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7023                 }
7024                 else
7025                 {
7026                         r_refdef.stats[r_stat_batch_entitystatic_count]++;
7027                         r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7028                         r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7029                         r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7030                 }
7031                 rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
7032                 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.data_vertex3f_vertexbuffer;
7033                 rsurface.modelvertex3f_bufferoffset = model->surfmesh.data_vertex3f_bufferoffset;
7034                 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7035                 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.data_svector3f_vertexbuffer;
7036                 rsurface.modelsvector3f_bufferoffset = model->surfmesh.data_svector3f_bufferoffset;
7037                 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7038                 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.data_tvector3f_vertexbuffer;
7039                 rsurface.modeltvector3f_bufferoffset = model->surfmesh.data_tvector3f_bufferoffset;
7040                 rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
7041                 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.data_normal3f_vertexbuffer;
7042                 rsurface.modelnormal3f_bufferoffset = model->surfmesh.data_normal3f_bufferoffset;
7043                 rsurface.modelgeneratedvertex = false;
7044         }
7045         rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
7046         rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.data_lightmapcolor4f_vertexbuffer;
7047         rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.data_lightmapcolor4f_bufferoffset;
7048         rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
7049         rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.data_texcoordtexture2f_vertexbuffer;
7050         rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.data_texcoordtexture2f_bufferoffset;
7051         rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
7052         rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.data_texcoordlightmap2f_vertexbuffer;
7053         rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.data_texcoordlightmap2f_bufferoffset;
7054         rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7055         rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.data_skeletalindex4ub_vertexbuffer;
7056         rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.data_skeletalindex4ub_bufferoffset;
7057         rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7058         rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.data_skeletalweight4ub_vertexbuffer;
7059         rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.data_skeletalweight4ub_bufferoffset;
7060         rsurface.modelelement3i = model->surfmesh.data_element3i;
7061         rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7062         rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7063         rsurface.modelelement3s = model->surfmesh.data_element3s;
7064         rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7065         rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7066         rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7067         rsurface.modelnumvertices = model->surfmesh.num_vertices;
7068         rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7069         rsurface.modelsurfaces = model->data_surfaces;
7070         rsurface.batchgeneratedvertex = false;
7071         rsurface.batchfirstvertex = 0;
7072         rsurface.batchnumvertices = 0;
7073         rsurface.batchfirsttriangle = 0;
7074         rsurface.batchnumtriangles = 0;
7075         rsurface.batchvertex3f  = NULL;
7076         rsurface.batchvertex3f_vertexbuffer = NULL;
7077         rsurface.batchvertex3f_bufferoffset = 0;
7078         rsurface.batchsvector3f = NULL;
7079         rsurface.batchsvector3f_vertexbuffer = NULL;
7080         rsurface.batchsvector3f_bufferoffset = 0;
7081         rsurface.batchtvector3f = NULL;
7082         rsurface.batchtvector3f_vertexbuffer = NULL;
7083         rsurface.batchtvector3f_bufferoffset = 0;
7084         rsurface.batchnormal3f  = NULL;
7085         rsurface.batchnormal3f_vertexbuffer = NULL;
7086         rsurface.batchnormal3f_bufferoffset = 0;
7087         rsurface.batchlightmapcolor4f = NULL;
7088         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7089         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7090         rsurface.batchtexcoordtexture2f = NULL;
7091         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7092         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7093         rsurface.batchtexcoordlightmap2f = NULL;
7094         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7095         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7096         rsurface.batchskeletalindex4ub = NULL;
7097         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7098         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7099         rsurface.batchskeletalweight4ub = NULL;
7100         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7101         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7102         rsurface.batchelement3i = NULL;
7103         rsurface.batchelement3i_indexbuffer = NULL;
7104         rsurface.batchelement3i_bufferoffset = 0;
7105         rsurface.batchelement3s = NULL;
7106         rsurface.batchelement3s_indexbuffer = NULL;
7107         rsurface.batchelement3s_bufferoffset = 0;
7108         rsurface.forcecurrenttextureupdate = false;
7109 }
7110
7111 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)
7112 {
7113         rsurface.entity = r_refdef.scene.worldentity;
7114         if (r != 1.0f || g != 1.0f || b != 1.0f || a != 1.0f) {
7115                 // HACK to provide a valid entity with modded colors to R_GetCurrentTexture.
7116                 // A better approach could be making this copy only once per frame.
7117                 static entity_render_t custom_entity;
7118                 int q;
7119                 custom_entity = *rsurface.entity;
7120                 for (q = 0; q < 3; ++q) {
7121                         float colormod = q == 0 ? r : q == 1 ? g : b;
7122                         custom_entity.render_fullbright[q] *= colormod;
7123                         custom_entity.render_modellight_ambient[q] *= colormod;
7124                         custom_entity.render_modellight_diffuse[q] *= colormod;
7125                         custom_entity.render_lightmap_ambient[q] *= colormod;
7126                         custom_entity.render_lightmap_diffuse[q] *= colormod;
7127                         custom_entity.render_rtlight_diffuse[q] *= colormod;
7128                 }
7129                 custom_entity.alpha *= a;
7130                 rsurface.entity = &custom_entity;
7131         }
7132         rsurface.skeleton = NULL;
7133         rsurface.ent_skinnum = 0;
7134         rsurface.ent_qwskin = -1;
7135         rsurface.ent_flags = entflags;
7136         rsurface.shadertime = r_refdef.scene.time - shadertime;
7137         rsurface.modelnumvertices = numvertices;
7138         rsurface.modelnumtriangles = numtriangles;
7139         rsurface.matrix = *matrix;
7140         rsurface.inversematrix = *inversematrix;
7141         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7142         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7143         R_EntityMatrix(&rsurface.matrix);
7144         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7145         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7146         rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7147         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7148         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7149         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7150         memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7151         rsurface.frameblend[0].lerp = 1;
7152         rsurface.ent_alttextures = false;
7153         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7154         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7155         rsurface.entityskeletaltransform3x4 = NULL;
7156         rsurface.entityskeletaltransform3x4buffer = NULL;
7157         rsurface.entityskeletaltransform3x4offset = 0;
7158         rsurface.entityskeletaltransform3x4size = 0;
7159         rsurface.entityskeletalnumtransforms = 0;
7160         r_refdef.stats[r_stat_batch_entitycustom_count]++;
7161         r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7162         r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7163         r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7164         if (wanttangents)
7165         {
7166                 rsurface.modelvertex3f = (float *)vertex3f;
7167                 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7168                 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7169                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7170         }
7171         else if (wantnormals)
7172         {
7173                 rsurface.modelvertex3f = (float *)vertex3f;
7174                 rsurface.modelsvector3f = NULL;
7175                 rsurface.modeltvector3f = NULL;
7176                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7177         }
7178         else
7179         {
7180                 rsurface.modelvertex3f = (float *)vertex3f;
7181                 rsurface.modelsvector3f = NULL;
7182                 rsurface.modeltvector3f = NULL;
7183                 rsurface.modelnormal3f = NULL;
7184         }
7185         rsurface.modelvertex3f_vertexbuffer = 0;
7186         rsurface.modelvertex3f_bufferoffset = 0;
7187         rsurface.modelsvector3f_vertexbuffer = 0;
7188         rsurface.modelsvector3f_bufferoffset = 0;
7189         rsurface.modeltvector3f_vertexbuffer = 0;
7190         rsurface.modeltvector3f_bufferoffset = 0;
7191         rsurface.modelnormal3f_vertexbuffer = 0;
7192         rsurface.modelnormal3f_bufferoffset = 0;
7193         rsurface.modelgeneratedvertex = true;
7194         rsurface.modellightmapcolor4f  = (float *)color4f;
7195         rsurface.modellightmapcolor4f_vertexbuffer = 0;
7196         rsurface.modellightmapcolor4f_bufferoffset = 0;
7197         rsurface.modeltexcoordtexture2f  = (float *)texcoord2f;
7198         rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7199         rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7200         rsurface.modeltexcoordlightmap2f  = NULL;
7201         rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7202         rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7203         rsurface.modelskeletalindex4ub = NULL;
7204         rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7205         rsurface.modelskeletalindex4ub_bufferoffset = 0;
7206         rsurface.modelskeletalweight4ub = NULL;
7207         rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7208         rsurface.modelskeletalweight4ub_bufferoffset = 0;
7209         rsurface.modelelement3i = (int *)element3i;
7210         rsurface.modelelement3i_indexbuffer = NULL;
7211         rsurface.modelelement3i_bufferoffset = 0;
7212         rsurface.modelelement3s = (unsigned short *)element3s;
7213         rsurface.modelelement3s_indexbuffer = NULL;
7214         rsurface.modelelement3s_bufferoffset = 0;
7215         rsurface.modellightmapoffsets = NULL;
7216         rsurface.modelsurfaces = NULL;
7217         rsurface.batchgeneratedvertex = false;
7218         rsurface.batchfirstvertex = 0;
7219         rsurface.batchnumvertices = 0;
7220         rsurface.batchfirsttriangle = 0;
7221         rsurface.batchnumtriangles = 0;
7222         rsurface.batchvertex3f  = NULL;
7223         rsurface.batchvertex3f_vertexbuffer = NULL;
7224         rsurface.batchvertex3f_bufferoffset = 0;
7225         rsurface.batchsvector3f = NULL;
7226         rsurface.batchsvector3f_vertexbuffer = NULL;
7227         rsurface.batchsvector3f_bufferoffset = 0;
7228         rsurface.batchtvector3f = NULL;
7229         rsurface.batchtvector3f_vertexbuffer = NULL;
7230         rsurface.batchtvector3f_bufferoffset = 0;
7231         rsurface.batchnormal3f  = NULL;
7232         rsurface.batchnormal3f_vertexbuffer = NULL;
7233         rsurface.batchnormal3f_bufferoffset = 0;
7234         rsurface.batchlightmapcolor4f = NULL;
7235         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7236         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7237         rsurface.batchtexcoordtexture2f = NULL;
7238         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7239         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7240         rsurface.batchtexcoordlightmap2f = NULL;
7241         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7242         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7243         rsurface.batchskeletalindex4ub = NULL;
7244         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7245         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7246         rsurface.batchskeletalweight4ub = NULL;
7247         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7248         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7249         rsurface.batchelement3i = NULL;
7250         rsurface.batchelement3i_indexbuffer = NULL;
7251         rsurface.batchelement3i_bufferoffset = 0;
7252         rsurface.batchelement3s = NULL;
7253         rsurface.batchelement3s_indexbuffer = NULL;
7254         rsurface.batchelement3s_bufferoffset = 0;
7255         rsurface.forcecurrenttextureupdate = true;
7256
7257         if (rsurface.modelnumvertices && rsurface.modelelement3i)
7258         {
7259                 if ((wantnormals || wanttangents) && !normal3f)
7260                 {
7261                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7262                         Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7263                 }
7264                 if (wanttangents && !svector3f)
7265                 {
7266                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7267                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7268                         Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7269                 }
7270         }
7271 }
7272
7273 float RSurf_FogPoint(const float *v)
7274 {
7275         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7276         float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7277         float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7278         float FogHeightFade = r_refdef.fogheightfade;
7279         float fogfrac;
7280         unsigned int fogmasktableindex;
7281         if (r_refdef.fogplaneviewabove)
7282                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7283         else
7284                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7285         fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7286         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7287 }
7288
7289 float RSurf_FogVertex(const float *v)
7290 {
7291         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7292         float FogPlaneViewDist = rsurface.fogplaneviewdist;
7293         float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7294         float FogHeightFade = rsurface.fogheightfade;
7295         float fogfrac;
7296         unsigned int fogmasktableindex;
7297         if (r_refdef.fogplaneviewabove)
7298                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7299         else
7300                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7301         fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7302         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7303 }
7304
7305 void RSurf_UploadBuffersForBatch(void)
7306 {
7307         // 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)
7308         // note that if rsurface.batchvertex3f_vertexbuffer is NULL, dynamicvertex is forced as we don't account for the proper base vertex here.
7309         if (rsurface.batchvertex3f && !rsurface.batchvertex3f_vertexbuffer)
7310                 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
7311         if (rsurface.batchsvector3f && !rsurface.batchsvector3f_vertexbuffer)
7312                 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
7313         if (rsurface.batchtvector3f && !rsurface.batchtvector3f_vertexbuffer)
7314                 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
7315         if (rsurface.batchnormal3f && !rsurface.batchnormal3f_vertexbuffer)
7316                 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
7317         if (rsurface.batchlightmapcolor4f && !rsurface.batchlightmapcolor4f_vertexbuffer)
7318                 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
7319         if (rsurface.batchtexcoordtexture2f && !rsurface.batchtexcoordtexture2f_vertexbuffer)
7320                 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
7321         if (rsurface.batchtexcoordlightmap2f && !rsurface.batchtexcoordlightmap2f_vertexbuffer)
7322                 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
7323         if (rsurface.batchskeletalindex4ub && !rsurface.batchskeletalindex4ub_vertexbuffer)
7324                 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
7325         if (rsurface.batchskeletalweight4ub && !rsurface.batchskeletalweight4ub_vertexbuffer)
7326                 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
7327
7328         if (rsurface.batchelement3s && !rsurface.batchelement3s_indexbuffer)
7329                 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
7330         else if (rsurface.batchelement3i && !rsurface.batchelement3i_indexbuffer)
7331                 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
7332
7333         R_Mesh_VertexPointer(     3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
7334         R_Mesh_ColorPointer(      4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
7335         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
7336         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
7337         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
7338         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
7339         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
7340         R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
7341         R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
7342         R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
7343 }
7344
7345 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7346 {
7347         int i;
7348         for (i = 0;i < numelements;i++)
7349                 outelement3i[i] = inelement3i[i] + adjust;
7350 }
7351
7352 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7353 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7354 {
7355         int deformindex;
7356         int firsttriangle;
7357         int numtriangles;
7358         int firstvertex;
7359         int endvertex;
7360         int numvertices;
7361         int surfacefirsttriangle;
7362         int surfacenumtriangles;
7363         int surfacefirstvertex;
7364         int surfaceendvertex;
7365         int surfacenumvertices;
7366         int batchnumsurfaces = texturenumsurfaces;
7367         int batchnumvertices;
7368         int batchnumtriangles;
7369         int i, j;
7370         qboolean gaps;
7371         qboolean dynamicvertex;
7372         float amplitude;
7373         float animpos;
7374         float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7375         float waveparms[4];
7376         unsigned char *ub;
7377         q3shaderinfo_deform_t *deform;
7378         const msurface_t *surface, *firstsurface;
7379         if (!texturenumsurfaces)
7380                 return;
7381         // find vertex range of this surface batch
7382         gaps = false;
7383         firstsurface = texturesurfacelist[0];
7384         firsttriangle = firstsurface->num_firsttriangle;
7385         batchnumvertices = 0;
7386         batchnumtriangles = 0;
7387         firstvertex = endvertex = firstsurface->num_firstvertex;
7388         for (i = 0;i < texturenumsurfaces;i++)
7389         {
7390                 surface = texturesurfacelist[i];
7391                 if (surface != firstsurface + i)
7392                         gaps = true;
7393                 surfacefirstvertex = surface->num_firstvertex;
7394                 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7395                 surfacenumvertices = surface->num_vertices;
7396                 surfacenumtriangles = surface->num_triangles;
7397                 if (firstvertex > surfacefirstvertex)
7398                         firstvertex = surfacefirstvertex;
7399                 if (endvertex < surfaceendvertex)
7400                         endvertex = surfaceendvertex;
7401                 batchnumvertices += surfacenumvertices;
7402                 batchnumtriangles += surfacenumtriangles;
7403         }
7404
7405         r_refdef.stats[r_stat_batch_batches]++;
7406         if (gaps)
7407                 r_refdef.stats[r_stat_batch_withgaps]++;
7408         r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7409         r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7410         r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7411
7412         // we now know the vertex range used, and if there are any gaps in it
7413         rsurface.batchfirstvertex = firstvertex;
7414         rsurface.batchnumvertices = endvertex - firstvertex;
7415         rsurface.batchfirsttriangle = firsttriangle;
7416         rsurface.batchnumtriangles = batchnumtriangles;
7417
7418         // check if any dynamic vertex processing must occur
7419         dynamicvertex = false;
7420
7421         // we must use vertexbuffers for rendering, we can upload vertex buffers
7422         // easily enough but if the basevertex is non-zero it becomes more
7423         // difficult, so force dynamicvertex path in that case - it's suboptimal
7424         // but the most optimal case is to have the geometry sources provide their
7425         // own anyway.
7426         if (!rsurface.modelvertex3f_vertexbuffer && firstvertex != 0)
7427                 dynamicvertex = true;
7428
7429         // a cvar to force the dynamic vertex path to be taken, for debugging
7430         if (r_batch_debugdynamicvertexpath.integer)
7431         {
7432                 if (!dynamicvertex)
7433                 {
7434                         r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7435                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7436                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7437                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7438                 }
7439                 dynamicvertex = true;
7440         }
7441
7442         // if there is a chance of animated vertex colors, it's a dynamic batch
7443         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
7444         {
7445                 if (!dynamicvertex)
7446                 {
7447                         r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7448                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7449                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7450                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7451                 }
7452                 dynamicvertex = true;
7453         }
7454
7455         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7456         {
7457                 switch (deform->deform)
7458                 {
7459                 default:
7460                 case Q3DEFORM_PROJECTIONSHADOW:
7461                 case Q3DEFORM_TEXT0:
7462                 case Q3DEFORM_TEXT1:
7463                 case Q3DEFORM_TEXT2:
7464                 case Q3DEFORM_TEXT3:
7465                 case Q3DEFORM_TEXT4:
7466                 case Q3DEFORM_TEXT5:
7467                 case Q3DEFORM_TEXT6:
7468                 case Q3DEFORM_TEXT7:
7469                 case Q3DEFORM_NONE:
7470                         break;
7471                 case Q3DEFORM_AUTOSPRITE:
7472                         if (!dynamicvertex)
7473                         {
7474                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7475                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7476                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7477                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7478                         }
7479                         dynamicvertex = true;
7480                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7481                         break;
7482                 case Q3DEFORM_AUTOSPRITE2:
7483                         if (!dynamicvertex)
7484                         {
7485                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7486                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7487                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7488                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7489                         }
7490                         dynamicvertex = true;
7491                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7492                         break;
7493                 case Q3DEFORM_NORMAL:
7494                         if (!dynamicvertex)
7495                         {
7496                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7497                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7498                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7499                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7500                         }
7501                         dynamicvertex = true;
7502                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7503                         break;
7504                 case Q3DEFORM_WAVE:
7505                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7506                                 break; // if wavefunc is a nop, ignore this transform
7507                         if (!dynamicvertex)
7508                         {
7509                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7510                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7511                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7512                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7513                         }
7514                         dynamicvertex = true;
7515                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7516                         break;
7517                 case Q3DEFORM_BULGE:
7518                         if (!dynamicvertex)
7519                         {
7520                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7521                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7522                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7523                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7524                         }
7525                         dynamicvertex = true;
7526                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7527                         break;
7528                 case Q3DEFORM_MOVE:
7529                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7530                                 break; // if wavefunc is a nop, ignore this transform
7531                         if (!dynamicvertex)
7532                         {
7533                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7534                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7535                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7536                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7537                         }
7538                         dynamicvertex = true;
7539                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7540                         break;
7541                 }
7542         }
7543         if (rsurface.texture->materialshaderpass)
7544         {
7545                 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7546                 {
7547                 default:
7548                 case Q3TCGEN_TEXTURE:
7549                         break;
7550                 case Q3TCGEN_LIGHTMAP:
7551                         if (!dynamicvertex)
7552                         {
7553                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7554                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7555                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7556                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7557                         }
7558                         dynamicvertex = true;
7559                         batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7560                         break;
7561                 case Q3TCGEN_VECTOR:
7562                         if (!dynamicvertex)
7563                         {
7564                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7565                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7566                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7567                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7568                         }
7569                         dynamicvertex = true;
7570                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7571                         break;
7572                 case Q3TCGEN_ENVIRONMENT:
7573                         if (!dynamicvertex)
7574                         {
7575                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7576                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7577                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7578                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7579                         }
7580                         dynamicvertex = true;
7581                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7582                         break;
7583                 }
7584                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7585                 {
7586                         if (!dynamicvertex)
7587                         {
7588                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7589                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7590                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7591                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7592                         }
7593                         dynamicvertex = true;
7594                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7595                 }
7596         }
7597
7598         // the caller can specify BATCHNEED_NOGAPS to force a batch with
7599         // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7600         // we ensure this by treating the vertex batch as dynamic...
7601         if ((batchneed & BATCHNEED_ALWAYSCOPY) || ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0)))
7602         {
7603                 if (!dynamicvertex)
7604                 {
7605                         r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7606                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7607                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7608                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7609                 }
7610                 dynamicvertex = true;
7611         }
7612
7613         // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7614         if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7615                 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7616
7617         rsurface.batchvertex3f = rsurface.modelvertex3f;
7618         rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7619         rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7620         rsurface.batchsvector3f = rsurface.modelsvector3f;
7621         rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7622         rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7623         rsurface.batchtvector3f = rsurface.modeltvector3f;
7624         rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7625         rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7626         rsurface.batchnormal3f = rsurface.modelnormal3f;
7627         rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7628         rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7629         rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7630         rsurface.batchlightmapcolor4f_vertexbuffer  = rsurface.modellightmapcolor4f_vertexbuffer;
7631         rsurface.batchlightmapcolor4f_bufferoffset  = rsurface.modellightmapcolor4f_bufferoffset;
7632         rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7633         rsurface.batchtexcoordtexture2f_vertexbuffer  = rsurface.modeltexcoordtexture2f_vertexbuffer;
7634         rsurface.batchtexcoordtexture2f_bufferoffset  = rsurface.modeltexcoordtexture2f_bufferoffset;
7635         rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7636         rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7637         rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7638         rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7639         rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7640         rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7641         rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7642         rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7643         rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7644         rsurface.batchelement3i = rsurface.modelelement3i;
7645         rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7646         rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7647         rsurface.batchelement3s = rsurface.modelelement3s;
7648         rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7649         rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7650         rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7651         rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7652         rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7653         rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7654         rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7655
7656         // if any dynamic vertex processing has to occur in software, we copy the
7657         // entire surface list together before processing to rebase the vertices
7658         // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7659         //
7660         // if any gaps exist and we do not have a static vertex buffer, we have to
7661         // copy the surface list together to avoid wasting upload bandwidth on the
7662         // vertices in the gaps.
7663         //
7664         // if gaps exist and we have a static vertex buffer, we can choose whether
7665         // to combine the index buffer ranges into one dynamic index buffer or
7666         // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7667         //
7668         // in many cases the batch is reduced to one draw call.
7669
7670         rsurface.batchmultidraw = false;
7671         rsurface.batchmultidrawnumsurfaces = 0;
7672         rsurface.batchmultidrawsurfacelist = NULL;
7673
7674         if (!dynamicvertex)
7675         {
7676                 // static vertex data, just set pointers...
7677                 rsurface.batchgeneratedvertex = false;
7678                 // if there are gaps, we want to build a combined index buffer,
7679                 // otherwise use the original static buffer with an appropriate offset
7680                 if (gaps)
7681                 {
7682                         r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7683                         r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7684                         r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7685                         r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7686                         if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7687                         {
7688                                 rsurface.batchmultidraw = true;
7689                                 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7690                                 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7691                                 return;
7692                         }
7693                         // build a new triangle elements array for this batch
7694                         rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7695                         rsurface.batchfirsttriangle = 0;
7696                         numtriangles = 0;
7697                         for (i = 0;i < texturenumsurfaces;i++)
7698                         {
7699                                 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7700                                 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7701                                 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7702                                 numtriangles += surfacenumtriangles;
7703                         }
7704                         rsurface.batchelement3i_indexbuffer = NULL;
7705                         rsurface.batchelement3i_bufferoffset = 0;
7706                         rsurface.batchelement3s = NULL;
7707                         rsurface.batchelement3s_indexbuffer = NULL;
7708                         rsurface.batchelement3s_bufferoffset = 0;
7709                         if (endvertex <= 65536)
7710                         {
7711                                 // make a 16bit (unsigned short) index array if possible
7712                                 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7713                                 for (i = 0;i < numtriangles*3;i++)
7714                                         rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7715                         }
7716                 }
7717                 else
7718                 {
7719                         r_refdef.stats[r_stat_batch_fast_batches] += 1;
7720                         r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
7721                         r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
7722                         r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
7723                 }
7724                 return;
7725         }
7726
7727         // something needs software processing, do it for real...
7728         // we only directly handle separate array data in this case and then
7729         // generate interleaved data if needed...
7730         rsurface.batchgeneratedvertex = true;
7731         r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
7732         r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
7733         r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
7734         r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
7735
7736         // now copy the vertex data into a combined array and make an index array
7737         // (this is what Quake3 does all the time)
7738         // we also apply any skeletal animation here that would have been done in
7739         // the vertex shader, because most of the dynamic vertex animation cases
7740         // need actual vertex positions and normals
7741         //if (dynamicvertex)
7742         {
7743                 rsurface.batchvertex3f = NULL;
7744                 rsurface.batchvertex3f_vertexbuffer = NULL;
7745                 rsurface.batchvertex3f_bufferoffset = 0;
7746                 rsurface.batchsvector3f = NULL;
7747                 rsurface.batchsvector3f_vertexbuffer = NULL;
7748                 rsurface.batchsvector3f_bufferoffset = 0;
7749                 rsurface.batchtvector3f = NULL;
7750                 rsurface.batchtvector3f_vertexbuffer = NULL;
7751                 rsurface.batchtvector3f_bufferoffset = 0;
7752                 rsurface.batchnormal3f = NULL;
7753                 rsurface.batchnormal3f_vertexbuffer = NULL;
7754                 rsurface.batchnormal3f_bufferoffset = 0;
7755                 rsurface.batchlightmapcolor4f = NULL;
7756                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7757                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7758                 rsurface.batchtexcoordtexture2f = NULL;
7759                 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7760                 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7761                 rsurface.batchtexcoordlightmap2f = NULL;
7762                 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7763                 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7764                 rsurface.batchskeletalindex4ub = NULL;
7765                 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7766                 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7767                 rsurface.batchskeletalweight4ub = NULL;
7768                 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7769                 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7770                 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7771                 rsurface.batchelement3i_indexbuffer = NULL;
7772                 rsurface.batchelement3i_bufferoffset = 0;
7773                 rsurface.batchelement3s = NULL;
7774                 rsurface.batchelement3s_indexbuffer = NULL;
7775                 rsurface.batchelement3s_bufferoffset = 0;
7776                 rsurface.batchskeletaltransform3x4buffer = NULL;
7777                 rsurface.batchskeletaltransform3x4offset = 0;
7778                 rsurface.batchskeletaltransform3x4size = 0;
7779                 // we'll only be setting up certain arrays as needed
7780                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7781                         rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7782                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7783                         rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7784                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7785                 {
7786                         rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7787                         rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7788                 }
7789                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7790                         rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
7791                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7792                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7793                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7794                         rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7795                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7796                 {
7797                         rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7798                         rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7799                 }
7800                 numvertices = 0;
7801                 numtriangles = 0;
7802                 for (i = 0;i < texturenumsurfaces;i++)
7803                 {
7804                         surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
7805                         surfacenumvertices = texturesurfacelist[i]->num_vertices;
7806                         surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7807                         surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7808                         // copy only the data requested
7809                         if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
7810                         {
7811                                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7812                                 {
7813                                         if (rsurface.batchvertex3f)
7814                                                 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7815                                         else
7816                                                 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7817                                 }
7818                                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7819                                 {
7820                                         if (rsurface.modelnormal3f)
7821                                                 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7822                                         else
7823                                                 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7824                                 }
7825                                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7826                                 {
7827                                         if (rsurface.modelsvector3f)
7828                                         {
7829                                                 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7830                                                 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7831                                         }
7832                                         else
7833                                         {
7834                                                 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7835                                                 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7836                                         }
7837                                 }
7838                                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7839                                 {
7840                                         if (rsurface.modellightmapcolor4f)
7841                                                 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
7842                                         else
7843                                                 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
7844                                 }
7845                                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7846                                 {
7847                                         if (rsurface.modeltexcoordtexture2f)
7848                                                 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7849                                         else
7850                                                 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7851                                 }
7852                                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7853                                 {
7854                                         if (rsurface.modeltexcoordlightmap2f)
7855                                                 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7856                                         else
7857                                                 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7858                                 }
7859                                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7860                                 {
7861                                         if (rsurface.modelskeletalindex4ub)
7862                                         {
7863                                                 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7864                                                 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7865                                         }
7866                                         else
7867                                         {
7868                                                 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7869                                                 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7870                                                 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
7871                                                 for (j = 0;j < surfacenumvertices;j++)
7872                                                         ub[j*4] = 255;
7873                                         }
7874                                 }
7875                         }
7876                         RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
7877                         numvertices += surfacenumvertices;
7878                         numtriangles += surfacenumtriangles;
7879                 }
7880
7881                 // generate a 16bit index array as well if possible
7882                 // (in general, dynamic batches fit)
7883                 if (numvertices <= 65536)
7884                 {
7885                         rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7886                         for (i = 0;i < numtriangles*3;i++)
7887                                 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7888                 }
7889
7890                 // since we've copied everything, the batch now starts at 0
7891                 rsurface.batchfirstvertex = 0;
7892                 rsurface.batchnumvertices = batchnumvertices;
7893                 rsurface.batchfirsttriangle = 0;
7894                 rsurface.batchnumtriangles = batchnumtriangles;
7895         }
7896
7897         // apply skeletal animation that would have been done in the vertex shader
7898         if (rsurface.batchskeletaltransform3x4)
7899         {
7900                 const unsigned char *si;
7901                 const unsigned char *sw;
7902                 const float *t[4];
7903                 const float *b = rsurface.batchskeletaltransform3x4;
7904                 float *vp, *vs, *vt, *vn;
7905                 float w[4];
7906                 float m[3][4], n[3][4];
7907                 float tp[3], ts[3], tt[3], tn[3];
7908                 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
7909                 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
7910                 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
7911                 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
7912                 si = rsurface.batchskeletalindex4ub;
7913                 sw = rsurface.batchskeletalweight4ub;
7914                 vp = rsurface.batchvertex3f;
7915                 vs = rsurface.batchsvector3f;
7916                 vt = rsurface.batchtvector3f;
7917                 vn = rsurface.batchnormal3f;
7918                 memset(m[0], 0, sizeof(m));
7919                 memset(n[0], 0, sizeof(n));
7920                 for (i = 0;i < batchnumvertices;i++)
7921                 {
7922                         t[0] = b + si[0]*12;
7923                         if (sw[0] == 255)
7924                         {
7925                                 // common case - only one matrix
7926                                 m[0][0] = t[0][ 0];
7927                                 m[0][1] = t[0][ 1];
7928                                 m[0][2] = t[0][ 2];
7929                                 m[0][3] = t[0][ 3];
7930                                 m[1][0] = t[0][ 4];
7931                                 m[1][1] = t[0][ 5];
7932                                 m[1][2] = t[0][ 6];
7933                                 m[1][3] = t[0][ 7];
7934                                 m[2][0] = t[0][ 8];
7935                                 m[2][1] = t[0][ 9];
7936                                 m[2][2] = t[0][10];
7937                                 m[2][3] = t[0][11];
7938                         }
7939                         else if (sw[2] + sw[3])
7940                         {
7941                                 // blend 4 matrices
7942                                 t[1] = b + si[1]*12;
7943                                 t[2] = b + si[2]*12;
7944                                 t[3] = b + si[3]*12;
7945                                 w[0] = sw[0] * (1.0f / 255.0f);
7946                                 w[1] = sw[1] * (1.0f / 255.0f);
7947                                 w[2] = sw[2] * (1.0f / 255.0f);
7948                                 w[3] = sw[3] * (1.0f / 255.0f);
7949                                 // blend the matrices
7950                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
7951                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
7952                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
7953                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
7954                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
7955                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
7956                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
7957                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
7958                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
7959                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
7960                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
7961                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
7962                         }
7963                         else
7964                         {
7965                                 // blend 2 matrices
7966                                 t[1] = b + si[1]*12;
7967                                 w[0] = sw[0] * (1.0f / 255.0f);
7968                                 w[1] = sw[1] * (1.0f / 255.0f);
7969                                 // blend the matrices
7970                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
7971                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
7972                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
7973                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
7974                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
7975                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
7976                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
7977                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
7978                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
7979                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
7980                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
7981                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
7982                         }
7983                         si += 4;
7984                         sw += 4;
7985                         // modify the vertex
7986                         VectorCopy(vp, tp);
7987                         vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
7988                         vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
7989                         vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
7990                         vp += 3;
7991                         if (vn)
7992                         {
7993                                 // the normal transformation matrix is a set of cross products...
7994                                 CrossProduct(m[1], m[2], n[0]);
7995                                 CrossProduct(m[2], m[0], n[1]);
7996                                 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
7997                                 VectorCopy(vn, tn);
7998                                 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
7999                                 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8000                                 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8001                                 VectorNormalize(vn);
8002                                 vn += 3;
8003                                 if (vs)
8004                                 {
8005                                         VectorCopy(vs, ts);
8006                                         vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8007                                         vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8008                                         vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8009                                         VectorNormalize(vs);
8010                                         vs += 3;
8011                                         VectorCopy(vt, tt);
8012                                         vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8013                                         vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8014                                         vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8015                                         VectorNormalize(vt);
8016                                         vt += 3;
8017                                 }
8018                         }
8019                 }
8020                 rsurface.batchskeletaltransform3x4 = NULL;
8021                 rsurface.batchskeletalnumtransforms = 0;
8022         }
8023
8024         // q1bsp surfaces rendered in vertex color mode have to have colors
8025         // calculated based on lightstyles
8026         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
8027         {
8028                 // generate color arrays for the surfaces in this list
8029                 int c[4];
8030                 int scale;
8031                 int size3;
8032                 const int *offsets;
8033                 const unsigned char *lm;
8034                 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8035                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8036                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8037                 numvertices = 0;
8038                 for (i = 0;i < texturenumsurfaces;i++)
8039                 {
8040                         surface = texturesurfacelist[i];
8041                         offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8042                         surfacenumvertices = surface->num_vertices;
8043                         if (surface->lightmapinfo->samples)
8044                         {
8045                                 for (j = 0;j < surfacenumvertices;j++)
8046                                 {
8047                                         lm = surface->lightmapinfo->samples + offsets[j];
8048                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8049                                         VectorScale(lm, scale, c);
8050                                         if (surface->lightmapinfo->styles[1] != 255)
8051                                         {
8052                                                 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8053                                                 lm += size3;
8054                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8055                                                 VectorMA(c, scale, lm, c);
8056                                                 if (surface->lightmapinfo->styles[2] != 255)
8057                                                 {
8058                                                         lm += size3;
8059                                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8060                                                         VectorMA(c, scale, lm, c);
8061                                                         if (surface->lightmapinfo->styles[3] != 255)
8062                                                         {
8063                                                                 lm += size3;
8064                                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8065                                                                 VectorMA(c, scale, lm, c);
8066                                                         }
8067                                                 }
8068                                         }
8069                                         c[0] >>= 7;
8070                                         c[1] >>= 7;
8071                                         c[2] >>= 7;
8072                                         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);
8073                                         numvertices++;
8074                                 }
8075                         }
8076                         else
8077                         {
8078                                 for (j = 0;j < surfacenumvertices;j++)
8079                                 {
8080                                         Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8081                                         numvertices++;
8082                                 }
8083                         }
8084                 }
8085         }
8086
8087         // if vertices are deformed (sprite flares and things in maps, possibly
8088         // water waves, bulges and other deformations), modify the copied vertices
8089         // in place
8090         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8091         {
8092                 float scale;
8093                 switch (deform->deform)
8094                 {
8095                 default:
8096                 case Q3DEFORM_PROJECTIONSHADOW:
8097                 case Q3DEFORM_TEXT0:
8098                 case Q3DEFORM_TEXT1:
8099                 case Q3DEFORM_TEXT2:
8100                 case Q3DEFORM_TEXT3:
8101                 case Q3DEFORM_TEXT4:
8102                 case Q3DEFORM_TEXT5:
8103                 case Q3DEFORM_TEXT6:
8104                 case Q3DEFORM_TEXT7:
8105                 case Q3DEFORM_NONE:
8106                         break;
8107                 case Q3DEFORM_AUTOSPRITE:
8108                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8109                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8110                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8111                         VectorNormalize(newforward);
8112                         VectorNormalize(newright);
8113                         VectorNormalize(newup);
8114 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8115 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8116 //                      rsurface.batchvertex3f_bufferoffset = 0;
8117 //                      rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8118 //                      rsurface.batchsvector3f_vertexbuffer = NULL;
8119 //                      rsurface.batchsvector3f_bufferoffset = 0;
8120 //                      rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8121 //                      rsurface.batchtvector3f_vertexbuffer = NULL;
8122 //                      rsurface.batchtvector3f_bufferoffset = 0;
8123 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8124 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8125 //                      rsurface.batchnormal3f_bufferoffset = 0;
8126                         // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8127                         if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8128                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8129                         if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8130                                 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);
8131                         // a single autosprite surface can contain multiple sprites...
8132                         for (j = 0;j < batchnumvertices - 3;j += 4)
8133                         {
8134                                 VectorClear(center);
8135                                 for (i = 0;i < 4;i++)
8136                                         VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8137                                 VectorScale(center, 0.25f, center);
8138                                 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8139                                 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8140                                 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8141                                 for (i = 0;i < 4;i++)
8142                                 {
8143                                         VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8144                                         VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8145                                 }
8146                         }
8147                         // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8148                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8149                         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);
8150                         break;
8151                 case Q3DEFORM_AUTOSPRITE2:
8152                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8153                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8154                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8155                         VectorNormalize(newforward);
8156                         VectorNormalize(newright);
8157                         VectorNormalize(newup);
8158 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8159 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8160 //                      rsurface.batchvertex3f_bufferoffset = 0;
8161                         {
8162                                 const float *v1, *v2;
8163                                 vec3_t start, end;
8164                                 float f, l;
8165                                 struct
8166                                 {
8167                                         float length2;
8168                                         const float *v1;
8169                                         const float *v2;
8170                                 }
8171                                 shortest[2];
8172                                 memset(shortest, 0, sizeof(shortest));
8173                                 // a single autosprite surface can contain multiple sprites...
8174                                 for (j = 0;j < batchnumvertices - 3;j += 4)
8175                                 {
8176                                         VectorClear(center);
8177                                         for (i = 0;i < 4;i++)
8178                                                 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8179                                         VectorScale(center, 0.25f, center);
8180                                         // find the two shortest edges, then use them to define the
8181                                         // axis vectors for rotating around the central axis
8182                                         for (i = 0;i < 6;i++)
8183                                         {
8184                                                 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8185                                                 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8186                                                 l = VectorDistance2(v1, v2);
8187                                                 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8188                                                 if (v1[2] != v2[2])
8189                                                         l += (1.0f / 1024.0f);
8190                                                 if (shortest[0].length2 > l || i == 0)
8191                                                 {
8192                                                         shortest[1] = shortest[0];
8193                                                         shortest[0].length2 = l;
8194                                                         shortest[0].v1 = v1;
8195                                                         shortest[0].v2 = v2;
8196                                                 }
8197                                                 else if (shortest[1].length2 > l || i == 1)
8198                                                 {
8199                                                         shortest[1].length2 = l;
8200                                                         shortest[1].v1 = v1;
8201                                                         shortest[1].v2 = v2;
8202                                                 }
8203                                         }
8204                                         VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8205                                         VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8206                                         // this calculates the right vector from the shortest edge
8207                                         // and the up vector from the edge midpoints
8208                                         VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8209                                         VectorNormalize(right);
8210                                         VectorSubtract(end, start, up);
8211                                         VectorNormalize(up);
8212                                         // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8213                                         VectorSubtract(rsurface.localvieworigin, center, forward);
8214                                         //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8215                                         VectorNegate(forward, forward);
8216                                         VectorReflect(forward, 0, up, forward);
8217                                         VectorNormalize(forward);
8218                                         CrossProduct(up, forward, newright);
8219                                         VectorNormalize(newright);
8220                                         // rotate the quad around the up axis vector, this is made
8221                                         // especially easy by the fact we know the quad is flat,
8222                                         // so we only have to subtract the center position and
8223                                         // measure distance along the right vector, and then
8224                                         // multiply that by the newright vector and add back the
8225                                         // center position
8226                                         // we also need to subtract the old position to undo the
8227                                         // displacement from the center, which we do with a
8228                                         // DotProduct, the subtraction/addition of center is also
8229                                         // optimized into DotProducts here
8230                                         l = DotProduct(right, center);
8231                                         for (i = 0;i < 4;i++)
8232                                         {
8233                                                 v1 = rsurface.batchvertex3f + 3*(j+i);
8234                                                 f = DotProduct(right, v1) - l;
8235                                                 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8236                                         }
8237                                 }
8238                         }
8239                         if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8240                         {
8241 //                              rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8242 //                              rsurface.batchnormal3f_vertexbuffer = NULL;
8243 //                              rsurface.batchnormal3f_bufferoffset = 0;
8244                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8245                         }
8246                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8247                         {
8248 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8249 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8250 //                              rsurface.batchsvector3f_bufferoffset = 0;
8251 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8252 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8253 //                              rsurface.batchtvector3f_bufferoffset = 0;
8254                                 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);
8255                         }
8256                         break;
8257                 case Q3DEFORM_NORMAL:
8258                         // deform the normals to make reflections wavey
8259                         rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8260                         rsurface.batchnormal3f_vertexbuffer = NULL;
8261                         rsurface.batchnormal3f_bufferoffset = 0;
8262                         for (j = 0;j < batchnumvertices;j++)
8263                         {
8264                                 float vertex[3];
8265                                 float *normal = rsurface.batchnormal3f + 3*j;
8266                                 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8267                                 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8268                                 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8269                                 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8270                                 VectorNormalize(normal);
8271                         }
8272                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8273                         {
8274 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8275 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8276 //                              rsurface.batchsvector3f_bufferoffset = 0;
8277 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8278 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8279 //                              rsurface.batchtvector3f_bufferoffset = 0;
8280                                 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);
8281                         }
8282                         break;
8283                 case Q3DEFORM_WAVE:
8284                         // deform vertex array to make wavey water and flags and such
8285                         waveparms[0] = deform->waveparms[0];
8286                         waveparms[1] = deform->waveparms[1];
8287                         waveparms[2] = deform->waveparms[2];
8288                         waveparms[3] = deform->waveparms[3];
8289                         if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8290                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8291                         // this is how a divisor of vertex influence on deformation
8292                         animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8293                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8294 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8295 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8296 //                      rsurface.batchvertex3f_bufferoffset = 0;
8297 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8298 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8299 //                      rsurface.batchnormal3f_bufferoffset = 0;
8300                         for (j = 0;j < batchnumvertices;j++)
8301                         {
8302                                 // if the wavefunc depends on time, evaluate it per-vertex
8303                                 if (waveparms[3])
8304                                 {
8305                                         waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8306                                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8307                                 }
8308                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8309                         }
8310                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8311                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8312                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8313                         {
8314 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8315 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8316 //                              rsurface.batchsvector3f_bufferoffset = 0;
8317 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8318 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8319 //                              rsurface.batchtvector3f_bufferoffset = 0;
8320                                 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);
8321                         }
8322                         break;
8323                 case Q3DEFORM_BULGE:
8324                         // deform vertex array to make the surface have moving bulges
8325 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8326 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8327 //                      rsurface.batchvertex3f_bufferoffset = 0;
8328 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8329 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8330 //                      rsurface.batchnormal3f_bufferoffset = 0;
8331                         for (j = 0;j < batchnumvertices;j++)
8332                         {
8333                                 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8334                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8335                         }
8336                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8337                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8338                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8339                         {
8340 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8341 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8342 //                              rsurface.batchsvector3f_bufferoffset = 0;
8343 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8344 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8345 //                              rsurface.batchtvector3f_bufferoffset = 0;
8346                                 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);
8347                         }
8348                         break;
8349                 case Q3DEFORM_MOVE:
8350                         // deform vertex array
8351                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8352                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8353                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8354                         VectorScale(deform->parms, scale, waveparms);
8355 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8356 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8357 //                      rsurface.batchvertex3f_bufferoffset = 0;
8358                         for (j = 0;j < batchnumvertices;j++)
8359                                 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8360                         break;
8361                 }
8362         }
8363
8364         if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8365         {
8366         // generate texcoords based on the chosen texcoord source
8367                 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8368                 {
8369                 default:
8370                 case Q3TCGEN_TEXTURE:
8371                         break;
8372                 case Q3TCGEN_LIGHTMAP:
8373         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8374         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8375         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8376                         if (rsurface.batchtexcoordlightmap2f)
8377                                 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8378                         break;
8379                 case Q3TCGEN_VECTOR:
8380         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8381         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8382         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8383                         for (j = 0;j < batchnumvertices;j++)
8384                         {
8385                                 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8386                                 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8387                         }
8388                         break;
8389                 case Q3TCGEN_ENVIRONMENT:
8390                         // make environment reflections using a spheremap
8391                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8392                         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8393                         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8394                         for (j = 0;j < batchnumvertices;j++)
8395                         {
8396                                 // identical to Q3A's method, but executed in worldspace so
8397                                 // carried models can be shiny too
8398
8399                                 float viewer[3], d, reflected[3], worldreflected[3];
8400
8401                                 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8402                                 // VectorNormalize(viewer);
8403
8404                                 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8405
8406                                 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8407                                 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8408                                 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8409                                 // note: this is proportinal to viewer, so we can normalize later
8410
8411                                 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8412                                 VectorNormalize(worldreflected);
8413
8414                                 // note: this sphere map only uses world x and z!
8415                                 // so positive and negative y will LOOK THE SAME.
8416                                 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8417                                 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8418                         }
8419                         break;
8420                 }
8421                 // the only tcmod that needs software vertex processing is turbulent, so
8422                 // check for it here and apply the changes if needed
8423                 // and we only support that as the first one
8424                 // (handling a mixture of turbulent and other tcmods would be problematic
8425                 //  without punting it entirely to a software path)
8426                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8427                 {
8428                         amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8429                         animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8430         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8431         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8432         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8433                         for (j = 0;j < batchnumvertices;j++)
8434                         {
8435                                 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);
8436                                 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8437                         }
8438                 }
8439         }
8440 }
8441
8442 void RSurf_DrawBatch(void)
8443 {
8444         // sometimes a zero triangle surface (usually a degenerate patch) makes it
8445         // through the pipeline, killing it earlier in the pipeline would have
8446         // per-surface overhead rather than per-batch overhead, so it's best to
8447         // reject it here, before it hits glDraw.
8448         if (rsurface.batchnumtriangles == 0)
8449                 return;
8450 #if 0
8451         // batch debugging code
8452         if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8453         {
8454                 int i;
8455                 int j;
8456                 int c;
8457                 const int *e;
8458                 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8459                 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8460                 {
8461                         c = e[i];
8462                         for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8463                         {
8464                                 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8465                                 {
8466                                         if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8467                                                 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);
8468                                         break;
8469                                 }
8470                         }
8471                 }
8472         }
8473 #endif
8474         if (rsurface.batchmultidraw)
8475         {
8476                 // issue multiple draws rather than copying index data
8477                 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8478                 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8479                 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8480                 for (i = 0;i < numsurfaces;)
8481                 {
8482                         // combine consecutive surfaces as one draw
8483                         for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8484                                 if (surfacelist[j] != surfacelist[k] + 1)
8485                                         break;
8486                         firstvertex = surfacelist[i]->num_firstvertex;
8487                         endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8488                         firsttriangle = surfacelist[i]->num_firsttriangle;
8489                         endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8490                         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);
8491                         i = j;
8492                 }
8493         }
8494         else
8495         {
8496                 // there is only one consecutive run of index data (may have been combined)
8497                 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);
8498         }
8499 }
8500
8501 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8502 {
8503         // pick the closest matching water plane
8504         int planeindex, vertexindex, bestplaneindex = -1;
8505         float d, bestd;
8506         vec3_t vert;
8507         const float *v;
8508         r_waterstate_waterplane_t *p;
8509         qboolean prepared = false;
8510         bestd = 0;
8511         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8512         {
8513                 if(p->camera_entity != rsurface.texture->camera_entity)
8514                         continue;
8515                 d = 0;
8516                 if(!prepared)
8517                 {
8518                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8519                         prepared = true;
8520                         if(rsurface.batchnumvertices == 0)
8521                                 break;
8522                 }
8523                 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8524                 {
8525                         Matrix4x4_Transform(&rsurface.matrix, v, vert);
8526                         d += fabs(PlaneDiff(vert, &p->plane));
8527                 }
8528                 if (bestd > d || bestplaneindex < 0)
8529                 {
8530                         bestd = d;
8531                         bestplaneindex = planeindex;
8532                 }
8533         }
8534         return bestplaneindex;
8535         // NOTE: this MAY return a totally unrelated water plane; we can ignore
8536         // this situation though, as it might be better to render single larger
8537         // batches with useless stuff (backface culled for example) than to
8538         // render multiple smaller batches
8539 }
8540
8541 void RSurf_SetupDepthAndCulling(void)
8542 {
8543         // submodels are biased to avoid z-fighting with world surfaces that they
8544         // may be exactly overlapping (avoids z-fighting artifacts on certain
8545         // doors and things in Quake maps)
8546         GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8547         GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8548         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8549         GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8550 }
8551
8552 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8553 {
8554         int i, j;
8555         // transparent sky would be ridiculous
8556         if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8557                 return;
8558         R_SetupShader_Generic_NoTexture(false, false);
8559         skyrenderlater = true;
8560         RSurf_SetupDepthAndCulling();
8561         GL_DepthMask(true);
8562
8563         // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8564         if (r_sky_scissor.integer)
8565         {
8566                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8567                 for (i = 0; i < texturenumsurfaces; i++)
8568                 {
8569                         const msurface_t *surf = texturesurfacelist[i];
8570                         const float *v;
8571                         float p[3];
8572                         float mins[3], maxs[3];
8573                         int scissor[4];
8574                         for (j = 0, v = rsurface.batchvertex3f + 3 * surf->num_firstvertex; j < surf->num_vertices; j++, v += 3)
8575                         {
8576                                 Matrix4x4_Transform(&rsurface.matrix, v, p);
8577                                 if (j > 0)
8578                                 {
8579                                         if (mins[0] > p[0]) mins[0] = p[0];
8580                                         if (mins[1] > p[1]) mins[1] = p[1];
8581                                         if (mins[2] > p[2]) mins[2] = p[2];
8582                                         if (maxs[0] < p[0]) maxs[0] = p[0];
8583                                         if (maxs[1] < p[1]) maxs[1] = p[1];
8584                                         if (maxs[2] < p[2]) maxs[2] = p[2];
8585                                 }
8586                                 else
8587                                 {
8588                                         VectorCopy(p, mins);
8589                                         VectorCopy(p, maxs);
8590                                 }
8591                         }
8592                         if (!R_ScissorForBBox(mins, maxs, scissor))
8593                         {
8594                                 if (skyscissor[2])
8595                                 {
8596                                         if (skyscissor[0] > scissor[0])
8597                                         {
8598                                                 skyscissor[2] += skyscissor[0] - scissor[0];
8599                                                 skyscissor[0] = scissor[0];
8600                                         }
8601                                         if (skyscissor[1] > scissor[1])
8602                                         {
8603                                                 skyscissor[3] += skyscissor[1] - scissor[1];
8604                                                 skyscissor[1] = scissor[1];
8605                                         }
8606                                         if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8607                                                 skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8608                                         if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8609                                                 skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8610                                 }
8611                                 else
8612                                         Vector4Copy(scissor, skyscissor);
8613                         }
8614                 }
8615         }
8616
8617         // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8618         // skymasking on them, and Quake3 never did sky masking (unlike
8619         // software Quake and software Quake2), so disable the sky masking
8620         // in Quake3 maps as it causes problems with q3map2 sky tricks,
8621         // and skymasking also looks very bad when noclipping outside the
8622         // level, so don't use it then either.
8623         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)
8624         {
8625                 R_Mesh_ResetTextureState();
8626                 if (skyrendermasked)
8627                 {
8628                         R_SetupShader_DepthOrShadow(false, false, false);
8629                         // depth-only (masking)
8630                         GL_ColorMask(0, 0, 0, 0);
8631                         // just to make sure that braindead drivers don't draw
8632                         // anything despite that colormask...
8633                         GL_BlendFunc(GL_ZERO, GL_ONE);
8634                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8635                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8636                 }
8637                 else
8638                 {
8639                         R_SetupShader_Generic_NoTexture(false, false);
8640                         // fog sky
8641                         GL_BlendFunc(GL_ONE, GL_ZERO);
8642                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8643                         GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
8644                         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
8645                 }
8646                 RSurf_DrawBatch();
8647                 if (skyrendermasked)
8648                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8649         }
8650         R_Mesh_ResetTextureState();
8651         GL_Color(1, 1, 1, 1);
8652 }
8653
8654 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
8655 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
8656 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass, qboolean ui)
8657 {
8658         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
8659                 return;
8660         if (prepass)
8661         {
8662                 // render screenspace normalmap to texture
8663                 GL_DepthMask(true);
8664                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false);
8665                 RSurf_DrawBatch();
8666                 return;
8667         }
8668
8669         // bind lightmap texture
8670
8671         // water/refraction/reflection/camera surfaces have to be handled specially
8672         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
8673         {
8674                 int start, end, startplaneindex;
8675                 for (start = 0;start < texturenumsurfaces;start = end)
8676                 {
8677                         startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
8678                         if(startplaneindex < 0)
8679                         {
8680                                 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
8681                                 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
8682                                 end = start + 1;
8683                                 continue;
8684                         }
8685                         for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
8686                                 ;
8687                         // now that we have a batch using the same planeindex, render it
8688                         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
8689                         {
8690                                 // render water or distortion background
8691                                 GL_DepthMask(true);
8692                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8693                                 RSurf_DrawBatch();
8694                                 // blend surface on top
8695                                 GL_DepthMask(false);
8696                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false);
8697                                 RSurf_DrawBatch();
8698                         }
8699                         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
8700                         {
8701                                 // render surface with reflection texture as input
8702                                 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8703                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8704                                 RSurf_DrawBatch();
8705                         }
8706                 }
8707                 return;
8708         }
8709
8710         // render surface batch normally
8711         GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8712         R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0 || ui);
8713         RSurf_DrawBatch();
8714 }
8715
8716 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
8717 {
8718         int vi;
8719         int j;
8720         int texturesurfaceindex;
8721         int k;
8722         const msurface_t *surface;
8723         float surfacecolor4f[4];
8724
8725 //      R_Mesh_ResetTextureState();
8726         R_SetupShader_Generic_NoTexture(false, false);
8727
8728         GL_BlendFunc(GL_ONE, GL_ZERO);
8729         GL_DepthMask(writedepth);
8730
8731         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
8732         vi = 0;
8733         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8734         {
8735                 surface = texturesurfacelist[texturesurfaceindex];
8736                 k = (int)(((size_t)surface) / sizeof(msurface_t));
8737                 Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
8738                 for (j = 0;j < surface->num_vertices;j++)
8739                 {
8740                         Vector4Copy(surfacecolor4f, rsurface.batchlightmapcolor4f + 4 * vi);
8741                         vi++;
8742                 }
8743         }
8744         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchlightmapcolor4f, rsurface.batchtexcoordtexture2f);
8745         RSurf_DrawBatch();
8746 }
8747
8748 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass, qboolean ui)
8749 {
8750         CHECKGLERROR
8751         RSurf_SetupDepthAndCulling();
8752         if (r_showsurfaces.integer && r_refdef.view.showdebug)
8753         {
8754                 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
8755                 return;
8756         }
8757         switch (vid.renderpath)
8758         {
8759         case RENDERPATH_GL32:
8760         case RENDERPATH_GLES2:
8761                 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8762                 break;
8763         }
8764         CHECKGLERROR
8765 }
8766
8767 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
8768 {
8769         int i, j;
8770         int texturenumsurfaces, endsurface;
8771         texture_t *texture;
8772         const msurface_t *surface;
8773         const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
8774
8775         RSurf_ActiveModelEntity(ent, true, true, false);
8776
8777         if (r_transparentdepthmasking.integer)
8778         {
8779                 qboolean setup = false;
8780                 for (i = 0;i < numsurfaces;i = j)
8781                 {
8782                         j = i + 1;
8783                         surface = rsurface.modelsurfaces + surfacelist[i];
8784                         texture = surface->texture;
8785                         rsurface.texture = R_GetCurrentTexture(texture);
8786                         rsurface.lightmaptexture = NULL;
8787                         rsurface.deluxemaptexture = NULL;
8788                         rsurface.uselightmaptexture = false;
8789                         // scan ahead until we find a different texture
8790                         endsurface = min(i + 1024, numsurfaces);
8791                         texturenumsurfaces = 0;
8792                         texturesurfacelist[texturenumsurfaces++] = surface;
8793                         for (;j < endsurface;j++)
8794                         {
8795                                 surface = rsurface.modelsurfaces + surfacelist[j];
8796                                 if (texture != surface->texture)
8797                                         break;
8798                                 texturesurfacelist[texturenumsurfaces++] = surface;
8799                         }
8800                         if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
8801                                 continue;
8802                         // render the range of surfaces as depth
8803                         if (!setup)
8804                         {
8805                                 setup = true;
8806                                 GL_ColorMask(0,0,0,0);
8807                                 GL_Color(1,1,1,1);
8808                                 GL_DepthTest(true);
8809                                 GL_BlendFunc(GL_ONE, GL_ZERO);
8810                                 GL_DepthMask(true);
8811 //                              R_Mesh_ResetTextureState();
8812                         }
8813                         RSurf_SetupDepthAndCulling();
8814                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8815                         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8816                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8817                         RSurf_DrawBatch();
8818                 }
8819                 if (setup)
8820                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8821         }
8822
8823         for (i = 0;i < numsurfaces;i = j)
8824         {
8825                 j = i + 1;
8826                 surface = rsurface.modelsurfaces + surfacelist[i];
8827                 texture = surface->texture;
8828                 rsurface.texture = R_GetCurrentTexture(texture);
8829                 // scan ahead until we find a different texture
8830                 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
8831                 texturenumsurfaces = 0;
8832                 texturesurfacelist[texturenumsurfaces++] = surface;
8833                         rsurface.lightmaptexture = surface->lightmaptexture;
8834                         rsurface.deluxemaptexture = surface->deluxemaptexture;
8835                         rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
8836                         for (;j < endsurface;j++)
8837                         {
8838                                 surface = rsurface.modelsurfaces + surfacelist[j];
8839                                 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
8840                                         break;
8841                                 texturesurfacelist[texturenumsurfaces++] = surface;
8842                         }
8843                 // render the range of surfaces
8844                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false, false);
8845         }
8846         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
8847 }
8848
8849 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8850 {
8851         // transparent surfaces get pushed off into the transparent queue
8852         int surfacelistindex;
8853         const msurface_t *surface;
8854         vec3_t tempcenter, center;
8855         for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
8856         {
8857                 surface = texturesurfacelist[surfacelistindex];
8858                 if (r_transparent_sortsurfacesbynearest.integer)
8859                 {
8860                         tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
8861                         tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
8862                         tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
8863                 }
8864                 else
8865                 {
8866                         tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
8867                         tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
8868                         tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
8869                 }
8870                 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
8871                 if (rsurface.entity->transparent_offset) // transparent offset
8872                 {
8873                         center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
8874                         center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
8875                         center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
8876                 }
8877                 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);
8878         }
8879 }
8880
8881 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8882 {
8883         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
8884                 return;
8885         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
8886                 return;
8887         RSurf_SetupDepthAndCulling();
8888         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8889         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8890         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8891         RSurf_DrawBatch();
8892 }
8893
8894 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass, qboolean ui)
8895 {
8896         CHECKGLERROR
8897         if (ui)
8898                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8899         else if (depthonly)
8900                 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
8901         else if (prepass)
8902         {
8903                 if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
8904                         return;
8905                 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8906                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
8907                 else
8908                         R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8909         }
8910         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
8911                 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
8912         else if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
8913                 return;
8914         else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
8915         {
8916                 // in the deferred case, transparent surfaces were queued during prepass
8917                 if (!r_shadow_usingdeferredprepass)
8918                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
8919         }
8920         else
8921         {
8922                 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
8923                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass, ui);
8924         }
8925         CHECKGLERROR
8926 }
8927
8928 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass, qboolean ui)
8929 {
8930         int i, j;
8931         texture_t *texture;
8932         R_FrameData_SetMark();
8933         // break the surface list down into batches by texture and use of lightmapping
8934         for (i = 0;i < numsurfaces;i = j)
8935         {
8936                 j = i + 1;
8937                 // texture is the base texture pointer, rsurface.texture is the
8938                 // current frame/skin the texture is directing us to use (for example
8939                 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
8940                 // use skin 1 instead)
8941                 texture = surfacelist[i]->texture;
8942                 rsurface.texture = R_GetCurrentTexture(texture);
8943                 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
8944                 {
8945                         // if this texture is not the kind we want, skip ahead to the next one
8946                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
8947                                 ;
8948                         continue;
8949                 }
8950                 if(depthonly || prepass)
8951                 {
8952                         rsurface.lightmaptexture = NULL;
8953                         rsurface.deluxemaptexture = NULL;
8954                         rsurface.uselightmaptexture = false;
8955                         // simply scan ahead until we find a different texture or lightmap state
8956                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
8957                                 ;
8958                 }
8959                 else
8960                 {
8961                         rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
8962                         rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
8963                         rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
8964                         // simply scan ahead until we find a different texture or lightmap state
8965                         for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
8966                                 ;
8967                 }
8968                 // render the range of surfaces
8969                 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass, ui);
8970         }
8971         R_FrameData_ReturnToMark();
8972 }
8973
8974 float locboxvertex3f[6*4*3] =
8975 {
8976         1,0,1, 1,0,0, 1,1,0, 1,1,1,
8977         0,1,1, 0,1,0, 0,0,0, 0,0,1,
8978         1,1,1, 1,1,0, 0,1,0, 0,1,1,
8979         0,0,1, 0,0,0, 1,0,0, 1,0,1,
8980         0,0,1, 1,0,1, 1,1,1, 0,1,1,
8981         1,0,0, 0,0,0, 0,1,0, 1,1,0
8982 };
8983
8984 unsigned short locboxelements[6*2*3] =
8985 {
8986          0, 1, 2, 0, 2, 3,
8987          4, 5, 6, 4, 6, 7,
8988          8, 9,10, 8,10,11,
8989         12,13,14, 12,14,15,
8990         16,17,18, 16,18,19,
8991         20,21,22, 20,22,23
8992 };
8993
8994 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
8995 {
8996         int i, j;
8997         cl_locnode_t *loc = (cl_locnode_t *)ent;
8998         vec3_t mins, size;
8999         float vertex3f[6*4*3];
9000         CHECKGLERROR
9001         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9002         GL_DepthMask(false);
9003         GL_DepthRange(0, 1);
9004         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9005         GL_DepthTest(true);
9006         GL_CullFace(GL_NONE);
9007         R_EntityMatrix(&identitymatrix);
9008
9009 //      R_Mesh_ResetTextureState();
9010
9011         i = surfacelist[0];
9012         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9013                          ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9014                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9015                         surfacelist[0] < 0 ? 0.5f : 0.125f);
9016
9017         if (VectorCompare(loc->mins, loc->maxs))
9018         {
9019                 VectorSet(size, 2, 2, 2);
9020                 VectorMA(loc->mins, -0.5f, size, mins);
9021         }
9022         else
9023         {
9024                 VectorCopy(loc->mins, mins);
9025                 VectorSubtract(loc->maxs, loc->mins, size);
9026         }
9027
9028         for (i = 0;i < 6*4*3;)
9029                 for (j = 0;j < 3;j++, i++)
9030                         vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9031
9032         R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9033         R_SetupShader_Generic_NoTexture(false, false);
9034         R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9035 }
9036
9037 void R_DrawLocs(void)
9038 {
9039         int index;
9040         cl_locnode_t *loc, *nearestloc;
9041         vec3_t center;
9042         nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9043         for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9044         {
9045                 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9046                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9047         }
9048 }
9049
9050 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9051 {
9052         if (decalsystem->decals)
9053                 Mem_Free(decalsystem->decals);
9054         memset(decalsystem, 0, sizeof(*decalsystem));
9055 }
9056
9057 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)
9058 {
9059         tridecal_t *decal;
9060         tridecal_t *decals;
9061         int i;
9062
9063         // expand or initialize the system
9064         if (decalsystem->maxdecals <= decalsystem->numdecals)
9065         {
9066                 decalsystem_t old = *decalsystem;
9067                 qboolean useshortelements;
9068                 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9069                 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9070                 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)));
9071                 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9072                 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9073                 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9074                 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9075                 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9076                 if (decalsystem->numdecals)
9077                         memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9078                 if (old.decals)
9079                         Mem_Free(old.decals);
9080                 for (i = 0;i < decalsystem->maxdecals*3;i++)
9081                         decalsystem->element3i[i] = i;
9082                 if (useshortelements)
9083                         for (i = 0;i < decalsystem->maxdecals*3;i++)
9084                                 decalsystem->element3s[i] = i;
9085         }
9086
9087         // grab a decal and search for another free slot for the next one
9088         decals = decalsystem->decals;
9089         decal = decalsystem->decals + (i = decalsystem->freedecal++);
9090         for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9091                 ;
9092         decalsystem->freedecal = i;
9093         if (decalsystem->numdecals <= i)
9094                 decalsystem->numdecals = i + 1;
9095
9096         // initialize the decal
9097         decal->lived = 0;
9098         decal->triangleindex = triangleindex;
9099         decal->surfaceindex = surfaceindex;
9100         decal->decalsequence = decalsequence;
9101         decal->color4f[0][0] = c0[0];
9102         decal->color4f[0][1] = c0[1];
9103         decal->color4f[0][2] = c0[2];
9104         decal->color4f[0][3] = 1;
9105         decal->color4f[1][0] = c1[0];
9106         decal->color4f[1][1] = c1[1];
9107         decal->color4f[1][2] = c1[2];
9108         decal->color4f[1][3] = 1;
9109         decal->color4f[2][0] = c2[0];
9110         decal->color4f[2][1] = c2[1];
9111         decal->color4f[2][2] = c2[2];
9112         decal->color4f[2][3] = 1;
9113         decal->vertex3f[0][0] = v0[0];
9114         decal->vertex3f[0][1] = v0[1];
9115         decal->vertex3f[0][2] = v0[2];
9116         decal->vertex3f[1][0] = v1[0];
9117         decal->vertex3f[1][1] = v1[1];
9118         decal->vertex3f[1][2] = v1[2];
9119         decal->vertex3f[2][0] = v2[0];
9120         decal->vertex3f[2][1] = v2[1];
9121         decal->vertex3f[2][2] = v2[2];
9122         decal->texcoord2f[0][0] = t0[0];
9123         decal->texcoord2f[0][1] = t0[1];
9124         decal->texcoord2f[1][0] = t1[0];
9125         decal->texcoord2f[1][1] = t1[1];
9126         decal->texcoord2f[2][0] = t2[0];
9127         decal->texcoord2f[2][1] = t2[1];
9128         TriangleNormal(v0, v1, v2, decal->plane);
9129         VectorNormalize(decal->plane);
9130         decal->plane[3] = DotProduct(v0, decal->plane);
9131 }
9132
9133 extern cvar_t cl_decals_bias;
9134 extern cvar_t cl_decals_models;
9135 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9136 // baseparms, parms, temps
9137 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)
9138 {
9139         int cornerindex;
9140         int index;
9141         float v[9][3];
9142         const float *vertex3f;
9143         const float *normal3f;
9144         int numpoints;
9145         float points[2][9][3];
9146         float temp[3];
9147         float tc[9][2];
9148         float f;
9149         float c[9][4];
9150         const int *e;
9151
9152         e = rsurface.modelelement3i + 3*triangleindex;
9153
9154         vertex3f = rsurface.modelvertex3f;
9155         normal3f = rsurface.modelnormal3f;
9156
9157         if (normal3f)
9158         {
9159                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9160                 {
9161                         index = 3*e[cornerindex];
9162                         VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9163                 }
9164         }
9165         else
9166         {
9167                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9168                 {
9169                         index = 3*e[cornerindex];
9170                         VectorCopy(vertex3f + index, v[cornerindex]);
9171                 }
9172         }
9173
9174         // cull backfaces
9175         //TriangleNormal(v[0], v[1], v[2], normal);
9176         //if (DotProduct(normal, localnormal) < 0.0f)
9177         //      continue;
9178         // clip by each of the box planes formed from the projection matrix
9179         // if anything survives, we emit the decal
9180         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]);
9181         if (numpoints < 3)
9182                 return;
9183         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]);
9184         if (numpoints < 3)
9185                 return;
9186         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]);
9187         if (numpoints < 3)
9188                 return;
9189         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]);
9190         if (numpoints < 3)
9191                 return;
9192         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]);
9193         if (numpoints < 3)
9194                 return;
9195         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]);
9196         if (numpoints < 3)
9197                 return;
9198         // some part of the triangle survived, so we have to accept it...
9199         if (dynamic)
9200         {
9201                 // dynamic always uses the original triangle
9202                 numpoints = 3;
9203                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9204                 {
9205                         index = 3*e[cornerindex];
9206                         VectorCopy(vertex3f + index, v[cornerindex]);
9207                 }
9208         }
9209         for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9210         {
9211                 // convert vertex positions to texcoords
9212                 Matrix4x4_Transform(projection, v[cornerindex], temp);
9213                 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9214                 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9215                 // calculate distance fade from the projection origin
9216                 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9217                 f = bound(0.0f, f, 1.0f);
9218                 c[cornerindex][0] = r * f;
9219                 c[cornerindex][1] = g * f;
9220                 c[cornerindex][2] = b * f;
9221                 c[cornerindex][3] = 1.0f;
9222                 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9223         }
9224         if (dynamic)
9225                 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);
9226         else
9227                 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9228                         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);
9229 }
9230 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)
9231 {
9232         matrix4x4_t projection;
9233         decalsystem_t *decalsystem;
9234         qboolean dynamic;
9235         dp_model_t *model;
9236         const msurface_t *surface;
9237         const msurface_t *surfaces;
9238         const int *surfacelist;
9239         const texture_t *texture;
9240         int numtriangles;
9241         int numsurfacelist;
9242         int surfacelistindex;
9243         int surfaceindex;
9244         int triangleindex;
9245         float localorigin[3];
9246         float localnormal[3];
9247         float localmins[3];
9248         float localmaxs[3];
9249         float localsize;
9250         //float normal[3];
9251         float planes[6][4];
9252         float angles[3];
9253         bih_t *bih;
9254         int bih_triangles_count;
9255         int bih_triangles[256];
9256         int bih_surfaces[256];
9257
9258         decalsystem = &ent->decalsystem;
9259         model = ent->model;
9260         if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9261         {
9262                 R_DecalSystem_Reset(&ent->decalsystem);
9263                 return;
9264         }
9265
9266         if (!model->brush.data_leafs && !cl_decals_models.integer)
9267         {
9268                 if (decalsystem->model)
9269                         R_DecalSystem_Reset(decalsystem);
9270                 return;
9271         }
9272
9273         if (decalsystem->model != model)
9274                 R_DecalSystem_Reset(decalsystem);
9275         decalsystem->model = model;
9276
9277         RSurf_ActiveModelEntity(ent, true, false, false);
9278
9279         Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9280         Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9281         VectorNormalize(localnormal);
9282         localsize = worldsize*rsurface.inversematrixscale;
9283         localmins[0] = localorigin[0] - localsize;
9284         localmins[1] = localorigin[1] - localsize;
9285         localmins[2] = localorigin[2] - localsize;
9286         localmaxs[0] = localorigin[0] + localsize;
9287         localmaxs[1] = localorigin[1] + localsize;
9288         localmaxs[2] = localorigin[2] + localsize;
9289
9290         //VectorCopy(localnormal, planes[4]);
9291         //VectorVectors(planes[4], planes[2], planes[0]);
9292         AnglesFromVectors(angles, localnormal, NULL, false);
9293         AngleVectors(angles, planes[0], planes[2], planes[4]);
9294         VectorNegate(planes[0], planes[1]);
9295         VectorNegate(planes[2], planes[3]);
9296         VectorNegate(planes[4], planes[5]);
9297         planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9298         planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9299         planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9300         planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9301         planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9302         planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9303
9304 #if 1
9305 // works
9306 {
9307         matrix4x4_t forwardprojection;
9308         Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9309         Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9310 }
9311 #else
9312 // broken
9313 {
9314         float projectionvector[4][3];
9315         VectorScale(planes[0], ilocalsize, projectionvector[0]);
9316         VectorScale(planes[2], ilocalsize, projectionvector[1]);
9317         VectorScale(planes[4], ilocalsize, projectionvector[2]);
9318         projectionvector[0][0] = planes[0][0] * ilocalsize;
9319         projectionvector[0][1] = planes[1][0] * ilocalsize;
9320         projectionvector[0][2] = planes[2][0] * ilocalsize;
9321         projectionvector[1][0] = planes[0][1] * ilocalsize;
9322         projectionvector[1][1] = planes[1][1] * ilocalsize;
9323         projectionvector[1][2] = planes[2][1] * ilocalsize;
9324         projectionvector[2][0] = planes[0][2] * ilocalsize;
9325         projectionvector[2][1] = planes[1][2] * ilocalsize;
9326         projectionvector[2][2] = planes[2][2] * ilocalsize;
9327         projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9328         projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9329         projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9330         Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9331 }
9332 #endif
9333
9334         dynamic = model->surfmesh.isanimated;
9335         numsurfacelist = model->nummodelsurfaces;
9336         surfacelist = model->sortedmodelsurfaces;
9337         surfaces = model->data_surfaces;
9338
9339         bih = NULL;
9340         bih_triangles_count = -1;
9341         if(!dynamic)
9342         {
9343                 if(model->render_bih.numleafs)
9344                         bih = &model->render_bih;
9345                 else if(model->collision_bih.numleafs)
9346                         bih = &model->collision_bih;
9347         }
9348         if(bih)
9349                 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9350         if(bih_triangles_count == 0)
9351                 return;
9352         if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9353                 return;
9354         if(bih_triangles_count > 0)
9355         {
9356                 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9357                 {
9358                         surfaceindex = bih_surfaces[triangleindex];
9359                         surface = surfaces + surfaceindex;
9360                         texture = surface->texture;
9361                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9362                                 continue;
9363                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9364                                 continue;
9365                         R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9366                 }
9367         }
9368         else
9369         {
9370                 for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
9371                 {
9372                         surfaceindex = surfacelist[surfacelistindex];
9373                         surface = surfaces + surfaceindex;
9374                         // check cull box first because it rejects more than any other check
9375                         if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9376                                 continue;
9377                         // skip transparent surfaces
9378                         texture = surface->texture;
9379                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9380                                 continue;
9381                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9382                                 continue;
9383                         numtriangles = surface->num_triangles;
9384                         for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9385                                 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9386                 }
9387         }
9388 }
9389
9390 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9391 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)
9392 {
9393         int renderentityindex;
9394         float worldmins[3];
9395         float worldmaxs[3];
9396         entity_render_t *ent;
9397
9398         worldmins[0] = worldorigin[0] - worldsize;
9399         worldmins[1] = worldorigin[1] - worldsize;
9400         worldmins[2] = worldorigin[2] - worldsize;
9401         worldmaxs[0] = worldorigin[0] + worldsize;
9402         worldmaxs[1] = worldorigin[1] + worldsize;
9403         worldmaxs[2] = worldorigin[2] + worldsize;
9404
9405         R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9406
9407         for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9408         {
9409                 ent = r_refdef.scene.entities[renderentityindex];
9410                 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9411                         continue;
9412
9413                 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9414         }
9415 }
9416
9417 typedef struct r_decalsystem_splatqueue_s
9418 {
9419         vec3_t worldorigin;
9420         vec3_t worldnormal;
9421         float color[4];
9422         float tcrange[4];
9423         float worldsize;
9424         unsigned int decalsequence;
9425 }
9426 r_decalsystem_splatqueue_t;
9427
9428 int r_decalsystem_numqueued = 0;
9429 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9430
9431 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)
9432 {
9433         r_decalsystem_splatqueue_t *queue;
9434
9435         if (r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9436                 return;
9437
9438         queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9439         VectorCopy(worldorigin, queue->worldorigin);
9440         VectorCopy(worldnormal, queue->worldnormal);
9441         Vector4Set(queue->color, r, g, b, a);
9442         Vector4Set(queue->tcrange, s1, t1, s2, t2);
9443         queue->worldsize = worldsize;
9444         queue->decalsequence = cl.decalsequence++;
9445 }
9446
9447 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9448 {
9449         int i;
9450         r_decalsystem_splatqueue_t *queue;
9451
9452         for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9453                 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);
9454         r_decalsystem_numqueued = 0;
9455 }
9456
9457 extern cvar_t cl_decals_max;
9458 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9459 {
9460         int i;
9461         decalsystem_t *decalsystem = &ent->decalsystem;
9462         int numdecals;
9463         unsigned int killsequence;
9464         tridecal_t *decal;
9465         float frametime;
9466         float lifetime;
9467
9468         if (!decalsystem->numdecals)
9469                 return;
9470
9471         if (r_showsurfaces.integer)
9472                 return;
9473
9474         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9475         {
9476                 R_DecalSystem_Reset(decalsystem);
9477                 return;
9478         }
9479
9480         killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9481         lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9482
9483         if (decalsystem->lastupdatetime)
9484                 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9485         else
9486                 frametime = 0;
9487         decalsystem->lastupdatetime = r_refdef.scene.time;
9488         numdecals = decalsystem->numdecals;
9489
9490         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9491         {
9492                 if (decal->color4f[0][3])
9493                 {
9494                         decal->lived += frametime;
9495                         if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9496                         {
9497                                 memset(decal, 0, sizeof(*decal));
9498                                 if (decalsystem->freedecal > i)
9499                                         decalsystem->freedecal = i;
9500                         }
9501                 }
9502         }
9503         decal = decalsystem->decals;
9504         while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9505                 numdecals--;
9506
9507         // collapse the array by shuffling the tail decals into the gaps
9508         for (;;)
9509         {
9510                 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
9511                         decalsystem->freedecal++;
9512                 if (decalsystem->freedecal == numdecals)
9513                         break;
9514                 decal[decalsystem->freedecal] = decal[--numdecals];
9515         }
9516
9517         decalsystem->numdecals = numdecals;
9518
9519         if (numdecals <= 0)
9520         {
9521                 // if there are no decals left, reset decalsystem
9522                 R_DecalSystem_Reset(decalsystem);
9523         }
9524 }
9525
9526 extern skinframe_t *decalskinframe;
9527 static void R_DrawModelDecals_Entity(entity_render_t *ent)
9528 {
9529         int i;
9530         decalsystem_t *decalsystem = &ent->decalsystem;
9531         int numdecals;
9532         tridecal_t *decal;
9533         float faderate;
9534         float alpha;
9535         float *v3f;
9536         float *c4f;
9537         float *t2f;
9538         const int *e;
9539         const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
9540         int numtris = 0;
9541
9542         numdecals = decalsystem->numdecals;
9543         if (!numdecals)
9544                 return;
9545
9546         if (r_showsurfaces.integer)
9547                 return;
9548
9549         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9550         {
9551                 R_DecalSystem_Reset(decalsystem);
9552                 return;
9553         }
9554
9555         // if the model is static it doesn't matter what value we give for
9556         // wantnormals and wanttangents, so this logic uses only rules applicable
9557         // to a model, knowing that they are meaningless otherwise
9558         RSurf_ActiveModelEntity(ent, false, false, false);
9559
9560         decalsystem->lastupdatetime = r_refdef.scene.time;
9561
9562         faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
9563
9564         // update vertex positions for animated models
9565         v3f = decalsystem->vertex3f;
9566         c4f = decalsystem->color4f;
9567         t2f = decalsystem->texcoord2f;
9568         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9569         {
9570                 if (!decal->color4f[0][3])
9571                         continue;
9572
9573                 if (surfacevisible && !surfacevisible[decal->surfaceindex])
9574                         continue;
9575
9576                 // skip backfaces
9577                 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
9578                         continue;
9579
9580                 // update color values for fading decals
9581                 if (decal->lived >= cl_decals_time.value)
9582                         alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
9583                 else
9584                         alpha = 1.0f;
9585
9586                 c4f[ 0] = decal->color4f[0][0] * alpha;
9587                 c4f[ 1] = decal->color4f[0][1] * alpha;
9588                 c4f[ 2] = decal->color4f[0][2] * alpha;
9589                 c4f[ 3] = 1;
9590                 c4f[ 4] = decal->color4f[1][0] * alpha;
9591                 c4f[ 5] = decal->color4f[1][1] * alpha;
9592                 c4f[ 6] = decal->color4f[1][2] * alpha;
9593                 c4f[ 7] = 1;
9594                 c4f[ 8] = decal->color4f[2][0] * alpha;
9595                 c4f[ 9] = decal->color4f[2][1] * alpha;
9596                 c4f[10] = decal->color4f[2][2] * alpha;
9597                 c4f[11] = 1;
9598
9599                 t2f[0] = decal->texcoord2f[0][0];
9600                 t2f[1] = decal->texcoord2f[0][1];
9601                 t2f[2] = decal->texcoord2f[1][0];
9602                 t2f[3] = decal->texcoord2f[1][1];
9603                 t2f[4] = decal->texcoord2f[2][0];
9604                 t2f[5] = decal->texcoord2f[2][1];
9605
9606                 // update vertex positions for animated models
9607                 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
9608                 {
9609                         e = rsurface.modelelement3i + 3*decal->triangleindex;
9610                         VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
9611                         VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
9612                         VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
9613                 }
9614                 else
9615                 {
9616                         VectorCopy(decal->vertex3f[0], v3f);
9617                         VectorCopy(decal->vertex3f[1], v3f + 3);
9618                         VectorCopy(decal->vertex3f[2], v3f + 6);
9619                 }
9620
9621                 if (r_refdef.fogenabled)
9622                 {
9623                         alpha = RSurf_FogVertex(v3f);
9624                         VectorScale(c4f, alpha, c4f);
9625                         alpha = RSurf_FogVertex(v3f + 3);
9626                         VectorScale(c4f + 4, alpha, c4f + 4);
9627                         alpha = RSurf_FogVertex(v3f + 6);
9628                         VectorScale(c4f + 8, alpha, c4f + 8);
9629                 }
9630
9631                 v3f += 9;
9632                 c4f += 12;
9633                 t2f += 6;
9634                 numtris++;
9635         }
9636
9637         if (numtris > 0)
9638         {
9639                 r_refdef.stats[r_stat_drawndecals] += numtris;
9640
9641                 // now render the decals all at once
9642                 // (this assumes they all use one particle font texture!)
9643                 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);
9644 //              R_Mesh_ResetTextureState();
9645                 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
9646                 GL_DepthMask(false);
9647                 GL_DepthRange(0, 1);
9648                 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
9649                 GL_DepthTest(true);
9650                 GL_CullFace(GL_NONE);
9651                 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
9652                 R_SetupShader_Generic(decalskinframe->base, false, false, false);
9653                 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
9654         }
9655 }
9656
9657 static void R_DrawModelDecals(void)
9658 {
9659         int i, numdecals;
9660
9661         // fade faster when there are too many decals
9662         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9663         for (i = 0;i < r_refdef.scene.numentities;i++)
9664                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9665
9666         R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
9667         for (i = 0;i < r_refdef.scene.numentities;i++)
9668                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9669                         R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
9670
9671         R_DecalSystem_ApplySplatEntitiesQueue();
9672
9673         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9674         for (i = 0;i < r_refdef.scene.numentities;i++)
9675                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9676
9677         r_refdef.stats[r_stat_totaldecals] += numdecals;
9678
9679         if (r_showsurfaces.integer || !r_drawdecals.integer)
9680                 return;
9681
9682         R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
9683
9684         for (i = 0;i < r_refdef.scene.numentities;i++)
9685         {
9686                 if (!r_refdef.viewcache.entityvisible[i])
9687                         continue;
9688                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9689                         R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
9690         }
9691 }
9692
9693 extern cvar_t mod_collision_bih;
9694 static void R_DrawDebugModel(void)
9695 {
9696         entity_render_t *ent = rsurface.entity;
9697         int i, j, flagsmask;
9698         const msurface_t *surface;
9699         dp_model_t *model = ent->model;
9700
9701         if (!sv.active  && !cls.demoplayback && ent != r_refdef.scene.worldentity)
9702                 return;
9703
9704         if (r_showoverdraw.value > 0)
9705         {
9706                 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
9707                 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9708                 R_SetupShader_Generic_NoTexture(false, false);
9709                 GL_DepthTest(false);
9710                 GL_DepthMask(false);
9711                 GL_DepthRange(0, 1);
9712                 GL_BlendFunc(GL_ONE, GL_ONE);
9713                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9714                 {
9715                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9716                                 continue;
9717                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9718                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9719                         {
9720                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
9721                                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
9722                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9723                                         GL_Color(c, 0, 0, 1.0f);
9724                                 else if (ent == r_refdef.scene.worldentity)
9725                                         GL_Color(c, c, c, 1.0f);
9726                                 else
9727                                         GL_Color(0, c, 0, 1.0f);
9728                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9729                                 RSurf_DrawBatch();
9730                         }
9731                 }
9732                 rsurface.texture = NULL;
9733         }
9734
9735         flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9736
9737 //      R_Mesh_ResetTextureState();
9738         R_SetupShader_Generic_NoTexture(false, false);
9739         GL_DepthRange(0, 1);
9740         GL_DepthTest(!r_showdisabledepthtest.integer);
9741         GL_DepthMask(false);
9742         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9743
9744         if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
9745         {
9746                 int triangleindex;
9747                 int bihleafindex;
9748                 qboolean cullbox = false;
9749                 const q3mbrush_t *brush;
9750                 const bih_t *bih = &model->collision_bih;
9751                 const bih_leaf_t *bihleaf;
9752                 float vertex3f[3][3];
9753                 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
9754                 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
9755                 {
9756                         if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
9757                                 continue;
9758                         switch (bihleaf->type)
9759                         {
9760                         case BIH_BRUSH:
9761                                 brush = model->brush.data_brushes + bihleaf->itemindex;
9762                                 if (brush->colbrushf && brush->colbrushf->numtriangles)
9763                                 {
9764                                         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);
9765                                         R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
9766                                         R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
9767                                 }
9768                                 break;
9769                         case BIH_COLLISIONTRIANGLE:
9770                                 triangleindex = bihleaf->itemindex;
9771                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
9772                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
9773                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
9774                                 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);
9775                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9776                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9777                                 break;
9778                         case BIH_RENDERTRIANGLE:
9779                                 triangleindex = bihleaf->itemindex;
9780                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
9781                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
9782                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
9783                                 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);
9784                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9785                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9786                                 break;
9787                         }
9788                 }
9789         }
9790
9791         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9792
9793 #ifndef USE_GLES2
9794         if (r_showtris.value > 0 && qglPolygonMode)
9795         {
9796                 if (r_showdisabledepthtest.integer)
9797                 {
9798                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9799                         GL_DepthMask(false);
9800                 }
9801                 else
9802                 {
9803                         GL_BlendFunc(GL_ONE, GL_ZERO);
9804                         GL_DepthMask(true);
9805                 }
9806                 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
9807                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9808                 {
9809                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9810                                 continue;
9811                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9812                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9813                         {
9814                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9815                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9816                                         GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
9817                                 else if (ent == r_refdef.scene.worldentity)
9818                                         GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
9819                                 else
9820                                         GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
9821                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9822                                 RSurf_DrawBatch();
9823                         }
9824                 }
9825                 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
9826                 rsurface.texture = NULL;
9827         }
9828
9829 # if 0
9830         // FIXME!  implement r_shownormals with just triangles
9831         if (r_shownormals.value != 0 && qglBegin)
9832         {
9833                 int l, k;
9834                 vec3_t v;
9835                 if (r_showdisabledepthtest.integer)
9836                 {
9837                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9838                         GL_DepthMask(false);
9839                 }
9840                 else
9841                 {
9842                         GL_BlendFunc(GL_ONE, GL_ZERO);
9843                         GL_DepthMask(true);
9844                 }
9845                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9846                 {
9847                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9848                                 continue;
9849                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9850                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9851                         {
9852                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9853                                 qglBegin(GL_LINES);
9854                                 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
9855                                 {
9856                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9857                                         {
9858                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9859                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9860                                                 qglVertex3f(v[0], v[1], v[2]);
9861                                                 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9862                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9863                                                 qglVertex3f(v[0], v[1], v[2]);
9864                                         }
9865                                 }
9866                                 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
9867                                 {
9868                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9869                                         {
9870                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9871                                                 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
9872                                                 qglVertex3f(v[0], v[1], v[2]);
9873                                                 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
9874                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9875                                                 qglVertex3f(v[0], v[1], v[2]);
9876                                         }
9877                                 }
9878                                 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
9879                                 {
9880                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9881                                         {
9882                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9883                                                 GL_Color(0, r_refdef.view.colorscale, 0, 1);
9884                                                 qglVertex3f(v[0], v[1], v[2]);
9885                                                 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
9886                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9887                                                 qglVertex3f(v[0], v[1], v[2]);
9888                                         }
9889                                 }
9890                                 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
9891                                 {
9892                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9893                                         {
9894                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9895                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9896                                                 qglVertex3f(v[0], v[1], v[2]);
9897                                                 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9898                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9899                                                 qglVertex3f(v[0], v[1], v[2]);
9900                                         }
9901                                 }
9902                                 qglEnd();
9903                                 CHECKGLERROR
9904                         }
9905                 }
9906                 rsurface.texture = NULL;
9907         }
9908 # endif
9909 #endif
9910 }
9911
9912 int r_maxsurfacelist = 0;
9913 const msurface_t **r_surfacelist = NULL;
9914 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass, qboolean ui)
9915 {
9916         int i, j, endj, flagsmask;
9917         dp_model_t *model = ent->model;
9918         msurface_t *surfaces;
9919         unsigned char *update;
9920         int numsurfacelist = 0;
9921         if (model == NULL)
9922                 return;
9923
9924         if (r_maxsurfacelist < model->num_surfaces)
9925         {
9926                 r_maxsurfacelist = model->num_surfaces;
9927                 if (r_surfacelist)
9928                         Mem_Free((msurface_t **)r_surfacelist);
9929                 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
9930         }
9931
9932         if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
9933                 RSurf_ActiveModelEntity(ent, false, false, false);
9934         else if (prepass)
9935                 RSurf_ActiveModelEntity(ent, true, true, true);
9936         else if (depthonly)
9937                 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
9938         else
9939                 RSurf_ActiveModelEntity(ent, true, true, false);
9940
9941         surfaces = model->data_surfaces;
9942         update = model->brushq1.lightmapupdateflags;
9943
9944         // update light styles
9945         if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0)
9946         {
9947                 model_brush_lightstyleinfo_t *style;
9948                 for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
9949                 {
9950                         if (style->value != r_refdef.scene.lightstylevalue[style->style])
9951                         {
9952                                 int *list = style->surfacelist;
9953                                 style->value = r_refdef.scene.lightstylevalue[style->style];
9954                                 for (j = 0;j < style->numsurfaces;j++)
9955                                         update[list[j]] = true;
9956                         }
9957                 }
9958         }
9959
9960         flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
9961
9962         if (debug)
9963         {
9964                 R_DrawDebugModel();
9965                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
9966                 return;
9967         }
9968
9969         rsurface.lightmaptexture = NULL;
9970         rsurface.deluxemaptexture = NULL;
9971         rsurface.uselightmaptexture = false;
9972         rsurface.texture = NULL;
9973         rsurface.rtlight = NULL;
9974         numsurfacelist = 0;
9975         // add visible surfaces to draw list
9976         if (ent == r_refdef.scene.worldentity)
9977         {
9978                 // for the world entity, check surfacevisible
9979                 for (i = 0;i < model->nummodelsurfaces;i++)
9980                 {
9981                         j = model->sortedmodelsurfaces[i];
9982                         if (r_refdef.viewcache.world_surfacevisible[j])
9983                                 r_surfacelist[numsurfacelist++] = surfaces + j;
9984                 }
9985         }
9986         else if (ui)
9987         {
9988                 // for ui we have to preserve the order of surfaces
9989                 for (i = 0; i < model->nummodelsurfaces; i++)
9990                         r_surfacelist[numsurfacelist++] = surfaces + model->firstmodelsurface + i;
9991         }
9992         else
9993         {
9994                 // add all surfaces
9995                 for (i = 0; i < model->nummodelsurfaces; i++)
9996                         r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
9997         }
9998         // don't do anything if there were no surfaces
9999         if (!numsurfacelist)
10000         {
10001                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10002                 return;
10003         }
10004         // update lightmaps if needed
10005         if (update)
10006         {
10007                 int updated = 0;
10008                 for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
10009                 {
10010                         if (update[j])
10011                         {
10012                                 updated++;
10013                                 R_BuildLightMap(ent, surfaces + j);
10014                         }
10015                 }
10016         }
10017
10018         R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass, ui);
10019
10020         // add to stats if desired
10021         if (r_speeds.integer && !skysurfaces && !depthonly)
10022         {
10023                 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10024                 for (j = 0;j < numsurfacelist;j++)
10025                         r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10026         }
10027
10028         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10029 }
10030
10031 void R_DebugLine(vec3_t start, vec3_t end)
10032 {
10033         dp_model_t *mod = CL_Mesh_UI();
10034         msurface_t *surf;
10035         int e0, e1, e2, e3;
10036         float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10037         float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10038         float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10039         vec4_t w[2], s[2];
10040
10041         // transform to screen coords first
10042         Vector4Set(w[0], start[0], start[1], start[2], 1);
10043         Vector4Set(w[1], end[0], end[1], end[2], 1);
10044         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10045         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10046         x1 = s[0][0] * vid_conwidth.value / vid.width;
10047         y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10048         x2 = s[1][0] * vid_conwidth.value / vid.width;
10049         y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10050         //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10051
10052         // add the line to the UI mesh for drawing later
10053
10054         // width is measured in real pixels
10055         if (fabs(x2 - x1) > fabs(y2 - y1))
10056         {
10057                 offsetx = 0;
10058                 offsety = 0.5f * width * vid_conheight.value / vid.height;
10059         }
10060         else
10061         {
10062                 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10063                 offsety = 0;
10064         }
10065         surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_WALL | MATERIALFLAG_VERTEXCOLOR | MATERIALFLAG_ALPHAGEN_VERTEX), true);
10066         e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10067         e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10068         e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10069         e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10070         Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10071         Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10072
10073 }
10074
10075
10076 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)
10077 {
10078         static texture_t texture;
10079
10080         // fake enough texture and surface state to render this geometry
10081
10082         texture.update_lastrenderframe = -1; // regenerate this texture
10083         texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10084         texture.basealpha = 1.0f;
10085         texture.currentskinframe = skinframe;
10086         texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10087         texture.offsetmapping = OFFSETMAPPING_OFF;
10088         texture.offsetscale = 1;
10089         texture.specularscalemod = 1;
10090         texture.specularpowermod = 1;
10091         texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10092
10093         R_DrawCustomSurface_Texture(&texture, texmatrix, materialflags, firstvertex, numvertices, firsttriangle, numtriangles, writedepth, prepass, ui);
10094 }
10095
10096 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)
10097 {
10098         static msurface_t surface;
10099         const msurface_t *surfacelist = &surface;
10100
10101         // fake enough texture and surface state to render this geometry
10102         surface.texture = texture;
10103         surface.num_triangles = numtriangles;
10104         surface.num_firsttriangle = firsttriangle;
10105         surface.num_vertices = numvertices;
10106         surface.num_firstvertex = firstvertex;
10107
10108         // now render it
10109         rsurface.texture = R_GetCurrentTexture(surface.texture);
10110         rsurface.lightmaptexture = NULL;
10111         rsurface.deluxemaptexture = NULL;
10112         rsurface.uselightmaptexture = false;
10113         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass, ui);
10114 }