]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
build: minor adjustments
[xonotic/darkplaces.git] / gl_rmain.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_main.c
21
22 #include "quakedef.h"
23 #include "r_shadow.h"
24 #include "polygon.h"
25 #include "image.h"
26 #include "ft2.h"
27 #include "csprogs.h"
28 #include "cl_video.h"
29 #include "cl_collision.h"
30
31 #ifdef WIN32
32 // Enable NVIDIA High Performance Graphics while using Integrated Graphics.
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36 __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
37 #ifdef __cplusplus
38 }
39 #endif
40 #endif
41
42 mempool_t *r_main_mempool;
43 rtexturepool_t *r_main_texturepool;
44
45 int r_textureframe = 0; ///< used only by R_GetCurrentTexture, incremented per view and per UI render
46
47 static qboolean r_loadnormalmap;
48 static qboolean r_loadgloss;
49 qboolean r_loadfog;
50 static qboolean r_loaddds;
51 static qboolean r_savedds;
52 static qboolean r_gpuskeletal;
53
54 //
55 // screen size info
56 //
57 r_refdef_t r_refdef;
58
59 cvar_t r_motionblur = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur", "0", "screen motionblur - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
60 cvar_t r_damageblur = {CVAR_CLIENT | CVAR_SAVE, "r_damageblur", "0", "screen motionblur based on damage - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
61 cvar_t r_motionblur_averaging = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_averaging", "0.1", "sliding average reaction time for velocity (higher = slower adaption to change)"};
62 cvar_t r_motionblur_randomize = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"};
63 cvar_t r_motionblur_minblur = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_minblur", "0.5", "factor of blur to apply at all times (always have this amount of blur no matter what the other factors are)"};
64 cvar_t r_motionblur_maxblur = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_maxblur", "0.9", "maxmimum amount of blur"};
65 cvar_t r_motionblur_velocityfactor = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_velocityfactor", "1", "factoring in of player velocity to the blur equation - the faster the player moves around the map, the more blur they get"};
66 cvar_t r_motionblur_velocityfactor_minspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_velocityfactor_minspeed", "400", "lower value of velocity when it starts to factor into blur equation"};
67 cvar_t r_motionblur_velocityfactor_maxspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_velocityfactor_maxspeed", "800", "upper value of velocity when it reaches the peak factor into blur equation"};
68 cvar_t r_motionblur_mousefactor = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_mousefactor", "2", "factoring in of mouse acceleration to the blur equation - the faster the player turns their mouse, the more blur they get"};
69 cvar_t r_motionblur_mousefactor_minspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_mousefactor_minspeed", "0", "lower value of mouse acceleration when it starts to factor into blur equation"};
70 cvar_t r_motionblur_mousefactor_maxspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_mousefactor_maxspeed", "50", "upper value of mouse acceleration when it reaches the peak factor into blur equation"};
71
72 cvar_t r_depthfirst = {CVAR_CLIENT | CVAR_SAVE, "r_depthfirst", "0", "renders a depth-only version of the scene before normal rendering begins to eliminate overdraw, values: 0 = off, 1 = world depth, 2 = world and model depth"};
73 cvar_t r_useinfinitefarclip = {CVAR_CLIENT | CVAR_SAVE, "r_useinfinitefarclip", "1", "enables use of a special kind of projection matrix that has an extremely large farclip"};
74 cvar_t r_farclip_base = {CVAR_CLIENT, "r_farclip_base", "65536", "farclip (furthest visible distance) for rendering when r_useinfinitefarclip is 0"};
75 cvar_t r_farclip_world = {CVAR_CLIENT, "r_farclip_world", "2", "adds map size to farclip multiplied by this value"};
76 cvar_t r_nearclip = {CVAR_CLIENT, "r_nearclip", "1", "distance from camera of nearclip plane" };
77 cvar_t r_deformvertexes = {CVAR_CLIENT, "r_deformvertexes", "1", "allows use of deformvertexes in shader files (can be turned off to check performance impact)"};
78 cvar_t r_transparent = {CVAR_CLIENT, "r_transparent", "1", "allows use of transparent surfaces (can be turned off to check performance impact)"};
79 cvar_t r_transparent_alphatocoverage = {CVAR_CLIENT, "r_transparent_alphatocoverage", "1", "enables GL_ALPHA_TO_COVERAGE antialiasing technique on alphablend and alphatest surfaces when using vid_samples 2 or higher"};
80 cvar_t r_transparent_sortsurfacesbynearest = {CVAR_CLIENT, "r_transparent_sortsurfacesbynearest", "1", "sort entity and world surfaces by nearest point on bounding box instead of using the center of the bounding box, usually reduces sorting artifacts"};
81 cvar_t r_transparent_useplanardistance = {CVAR_CLIENT, "r_transparent_useplanardistance", "0", "sort transparent meshes by distance from view plane rather than spherical distance to the chosen point"};
82 cvar_t r_showoverdraw = {CVAR_CLIENT, "r_showoverdraw", "0", "shows overlapping geometry"};
83 cvar_t r_showbboxes = {CVAR_CLIENT, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
84 cvar_t r_showbboxes_client = {CVAR_CLIENT, "r_showbboxes_client", "0", "shows bounding boxes of clientside qc entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
85 cvar_t r_showsurfaces = {CVAR_CLIENT, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 2 shows triangle draw order (for analyzing whether meshes are optimized for vertex cache)"};
86 cvar_t r_showtris = {CVAR_CLIENT, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
87 cvar_t r_shownormals = {CVAR_CLIENT, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
88 cvar_t r_showlighting = {CVAR_CLIENT, "r_showlighting", "0", "shows areas lit by lights, useful for finding out why some areas of a map render slowly (bright orange = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
89 cvar_t r_showcollisionbrushes = {CVAR_CLIENT, "r_showcollisionbrushes", "0", "draws collision brushes in quake3 maps (mode 1), mode 2 disables rendering of world (trippy!)"};
90 cvar_t r_showcollisionbrushes_polygonfactor = {CVAR_CLIENT, "r_showcollisionbrushes_polygonfactor", "-1", "expands outward the brush polygons a little bit, used to make collision brushes appear infront of walls"};
91 cvar_t r_showcollisionbrushes_polygonoffset = {CVAR_CLIENT, "r_showcollisionbrushes_polygonoffset", "0", "nudges brush polygon depth in hardware depth units, used to make collision brushes appear infront of walls"};
92 cvar_t r_showdisabledepthtest = {CVAR_CLIENT, "r_showdisabledepthtest", "0", "disables depth testing on r_show* cvars, allowing you to see what hidden geometry the graphics card is processing"};
93 cvar_t r_showspriteedges = {CVAR_CLIENT, "r_showspriteedges", "0", "renders a debug outline to show the polygon shape of each sprite frame rendered (may be 2 or more in case of interpolated animations), for debugging rendering bugs with specific view types"};
94 cvar_t r_showparticleedges = {CVAR_CLIENT, "r_showparticleedges", "0", "renders a debug outline to show the polygon shape of each particle, for debugging rendering bugs with specific view types"};
95 cvar_t r_drawportals = {CVAR_CLIENT, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
96 cvar_t r_drawentities = {CVAR_CLIENT, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
97 cvar_t r_draw2d = {CVAR_CLIENT, "r_draw2d","1", "draw 2D stuff (dangerous to turn off)"};
98 cvar_t r_drawworld = {CVAR_CLIENT, "r_drawworld","1", "draw world (most static stuff)"};
99 cvar_t r_drawviewmodel = {CVAR_CLIENT, "r_drawviewmodel","1", "draw your weapon model"};
100 cvar_t r_drawexteriormodel = {CVAR_CLIENT, "r_drawexteriormodel","1", "draw your player model (e.g. in chase cam, reflections)"};
101 cvar_t r_cullentities_trace = {CVAR_CLIENT, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
102 cvar_t r_cullentities_trace_entityocclusion = {CVAR_CLIENT, "r_cullentities_trace_entityocclusion", "1", "check for occluding entities such as doors, not just world hull"};
103 cvar_t r_cullentities_trace_samples = {CVAR_CLIENT, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling (in addition to center sample)"};
104 cvar_t r_cullentities_trace_tempentitysamples = {CVAR_CLIENT, "r_cullentities_trace_tempentitysamples", "-1", "number of samples to test for entity culling of temp entities (including all CSQC entities), -1 disables trace culling on these entities to prevent flicker (pvs still applies)"};
105 cvar_t r_cullentities_trace_enlarge = {CVAR_CLIENT, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
106 cvar_t r_cullentities_trace_expand = {CVAR_CLIENT, "r_cullentities_trace_expand", "0", "box expanded by this many units for entity culling"};
107 cvar_t r_cullentities_trace_pad = {CVAR_CLIENT, "r_cullentities_trace_pad", "8", "accept traces that hit within this many units of the box"};
108 cvar_t r_cullentities_trace_delay = {CVAR_CLIENT, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
109 cvar_t r_cullentities_trace_eyejitter = {CVAR_CLIENT, "r_cullentities_trace_eyejitter", "16", "randomly offset rays from the eye by this much to reduce the odds of flickering"};
110 cvar_t r_sortentities = {CVAR_CLIENT, "r_sortentities", "0", "sort entities before drawing (might be faster)"};
111 cvar_t r_speeds = {CVAR_CLIENT, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
112 cvar_t r_fullbright = {CVAR_CLIENT, "r_fullbright","0", "makes map very bright and renders faster"};
113
114 cvar_t r_fullbright_directed = {CVAR_CLIENT, "r_fullbright_directed", "0", "render fullbright things (unlit worldmodel and EF_FULLBRIGHT entities, but not fullbright shaders) using a constant light direction instead to add more depth while keeping uniform brightness"};
115 cvar_t r_fullbright_directed_ambient = {CVAR_CLIENT, "r_fullbright_directed_ambient", "0.5", "ambient light multiplier for directed fullbright"};
116 cvar_t r_fullbright_directed_diffuse = {CVAR_CLIENT, "r_fullbright_directed_diffuse", "0.75", "diffuse light multiplier for directed fullbright"};
117 cvar_t r_fullbright_directed_pitch = {CVAR_CLIENT, "r_fullbright_directed_pitch", "20", "constant pitch direction ('height') of the fake light source to use for fullbright"};
118 cvar_t r_fullbright_directed_pitch_relative = {CVAR_CLIENT, "r_fullbright_directed_pitch_relative", "0", "whether r_fullbright_directed_pitch is interpreted as absolute (0) or relative (1) pitch"};
119
120 cvar_t r_wateralpha = {CVAR_CLIENT | CVAR_SAVE, "r_wateralpha","1", "opacity of water polygons"};
121 cvar_t r_dynamic = {CVAR_CLIENT | CVAR_SAVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
122 cvar_t r_fullbrights = {CVAR_CLIENT | CVAR_SAVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
123 cvar_t r_shadows = {CVAR_CLIENT | CVAR_SAVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this); when set to 2, always cast the shadows in the direction set by r_shadows_throwdirection, otherwise use the model lighting."};
124 cvar_t r_shadows_darken = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_darken", "0.5", "how much shadowed areas will be darkened"};
125 cvar_t r_shadows_throwdistance = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
126 cvar_t r_shadows_throwdirection = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_throwdirection", "0 0 -1", "override throwing direction for r_shadows 2"};
127 cvar_t r_shadows_drawafterrtlighting = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_drawafterrtlighting", "0", "draw fake shadows AFTER realtime lightning is drawn. May be useful for simulating fast sunlight on large outdoor maps with only one noshadow rtlight. The price is less realistic appearance of dynamic light shadows."};
128 cvar_t r_shadows_castfrombmodels = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
129 cvar_t r_shadows_focus = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_focus", "0 0 0", "offset the shadowed area focus"};
130 cvar_t r_shadows_shadowmapscale = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_shadowmapscale", "0.25", "higher values increase shadowmap quality at a cost of area covered (multiply global shadowmap precision) for fake shadows. Needs shadowmapping ON."};
131 cvar_t r_shadows_shadowmapbias = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_shadowmapbias", "-1", "sets shadowmap bias for fake shadows. -1 sets the value of r_shadow_shadowmapping_bias. Needs shadowmapping ON."};
132 cvar_t r_q1bsp_skymasking = {CVAR_CLIENT, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
133 cvar_t r_polygonoffset_submodel_factor = {CVAR_CLIENT, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
134 cvar_t r_polygonoffset_submodel_offset = {CVAR_CLIENT, "r_polygonoffset_submodel_offset", "14", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
135 cvar_t r_polygonoffset_decals_factor = {CVAR_CLIENT, "r_polygonoffset_decals_factor", "0", "biases depth values of decals to prevent z-fighting artifacts"};
136 cvar_t r_polygonoffset_decals_offset = {CVAR_CLIENT, "r_polygonoffset_decals_offset", "-14", "biases depth values of decals to prevent z-fighting artifacts"};
137 cvar_t r_fog_exp2 = {CVAR_CLIENT, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"};
138 cvar_t r_fog_clear = {CVAR_CLIENT, "r_fog_clear", "1", "clears renderbuffer with fog color before render starts"};
139 cvar_t r_drawfog = {CVAR_CLIENT | CVAR_SAVE, "r_drawfog", "1", "allows one to disable fog rendering"};
140 cvar_t r_transparentdepthmasking = {CVAR_CLIENT | CVAR_SAVE, "r_transparentdepthmasking", "0", "enables depth writes on transparent meshes whose materially is normally opaque, this prevents seeing the inside of a transparent mesh"};
141 cvar_t r_transparent_sortmindist = {CVAR_CLIENT | CVAR_SAVE, "r_transparent_sortmindist", "0", "lower distance limit for transparent sorting"};
142 cvar_t r_transparent_sortmaxdist = {CVAR_CLIENT | CVAR_SAVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"};
143 cvar_t r_transparent_sortarraysize = {CVAR_CLIENT | CVAR_SAVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"};
144 cvar_t r_celshading = {CVAR_CLIENT | CVAR_SAVE, "r_celshading", "0", "cartoon-style light shading (OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9
145 cvar_t r_celoutlines = {CVAR_CLIENT | CVAR_SAVE, "r_celoutlines", "0", "cartoon-style outlines (requires r_shadow_deferred; OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9
146
147 cvar_t gl_fogenable = {CVAR_CLIENT, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
148 cvar_t gl_fogdensity = {CVAR_CLIENT, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
149 cvar_t gl_fogred = {CVAR_CLIENT, "gl_fogred","0.3", "nehahra fog color red value (for Nehahra compatibility only)"};
150 cvar_t gl_foggreen = {CVAR_CLIENT, "gl_foggreen","0.3", "nehahra fog color green value (for Nehahra compatibility only)"};
151 cvar_t gl_fogblue = {CVAR_CLIENT, "gl_fogblue","0.3", "nehahra fog color blue value (for Nehahra compatibility only)"};
152 cvar_t gl_fogstart = {CVAR_CLIENT, "gl_fogstart", "0", "nehahra fog start distance (for Nehahra compatibility only)"};
153 cvar_t gl_fogend = {CVAR_CLIENT, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
154 cvar_t gl_skyclip = {CVAR_CLIENT, "gl_skyclip", "4608", "nehahra farclip distance - the real fog end (for Nehahra compatibility only)"};
155
156 cvar_t r_texture_dds_load = {CVAR_CLIENT | CVAR_SAVE, "r_texture_dds_load", "0", "load compressed dds/filename.dds texture instead of filename.tga, if the file exists (requires driver support)"};
157 cvar_t r_texture_dds_save = {CVAR_CLIENT | CVAR_SAVE, "r_texture_dds_save", "0", "save compressed dds/filename.dds texture when filename.tga is loaded, so that it can be loaded instead next time"};
158
159 cvar_t r_textureunits = {CVAR_CLIENT, "r_textureunits", "32", "number of texture units to use in GL 1.1 and GL 1.3 rendering paths"};
160 static cvar_t gl_combine = {CVAR_CLIENT | CVAR_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"};
161 static cvar_t r_glsl = {CVAR_CLIENT | CVAR_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"};
162
163 cvar_t r_usedepthtextures = {CVAR_CLIENT | CVAR_SAVE, "r_usedepthtextures", "1", "use depth texture instead of depth renderbuffer where possible, uses less video memory but may render slower (or faster) depending on hardware"};
164 cvar_t r_viewfbo = {CVAR_CLIENT | CVAR_SAVE, "r_viewfbo", "0", "enables use of an 8bit (1) or 16bit (2) or 32bit (3) per component float framebuffer render, which may be at a different resolution than the video mode"};
165 cvar_t r_rendertarget_debug = {CVAR_CLIENT, "r_rendertarget_debug", "-1", "replaces the view with the contents of the specified render target (by number - note that these can fluctuate depending on scene)"};
166 cvar_t r_viewscale = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale", "1", "scaling factor for resolution of the fbo rendering method, must be > 0, can be above 1 for a costly antialiasing behavior, typical values are 0.5 for 1/4th as many pixels rendered, or 1 for normal rendering"};
167 cvar_t r_viewscale_fpsscaling = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling", "0", "change resolution based on framerate"};
168 cvar_t r_viewscale_fpsscaling_min = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_min", "0.0625", "worst acceptable quality"};
169 cvar_t r_viewscale_fpsscaling_multiply = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_multiply", "5", "adjust quality up or down by the frametime difference from 1.0/target, multiplied by this factor"};
170 cvar_t r_viewscale_fpsscaling_stepsize = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_stepsize", "0.01", "smallest adjustment to hit the target framerate (this value prevents minute oscillations)"};
171 cvar_t r_viewscale_fpsscaling_stepmax = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_stepmax", "1.00", "largest adjustment to hit the target framerate (this value prevents wild overshooting of the estimate)"};
172 cvar_t r_viewscale_fpsscaling_target = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_target", "70", "desired framerate"};
173
174 cvar_t r_glsl_skeletal = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_skeletal", "1", "render skeletal models faster using a gpu-skinning technique"};
175 cvar_t r_glsl_deluxemapping = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
176 cvar_t r_glsl_offsetmapping = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
177 cvar_t r_glsl_offsetmapping_steps = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_steps", "2", "offset mapping steps (note: too high values may be not supported by your GPU)"};
178 cvar_t r_glsl_offsetmapping_reliefmapping = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
179 cvar_t r_glsl_offsetmapping_reliefmapping_steps = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_steps", "10", "relief mapping steps (note: too high values may be not supported by your GPU)"};
180 cvar_t r_glsl_offsetmapping_reliefmapping_refinesteps = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_refinesteps", "5", "relief mapping refine steps (these are a binary search executed as the last step as given by r_glsl_offsetmapping_reliefmapping_steps)"};
181 cvar_t r_glsl_offsetmapping_scale = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
182 cvar_t r_glsl_offsetmapping_lod = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_lod", "0", "apply distance-based level-of-detail correction to number of offsetmappig steps, effectively making it render faster on large open-area maps"};
183 cvar_t r_glsl_offsetmapping_lod_distance = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_lod_distance", "32", "first LOD level distance, second level (-50% steps) is 2x of this, third (33%) - 3x etc."};
184 cvar_t r_glsl_postprocess = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess", "0", "use a GLSL postprocessing shader"};
185 cvar_t r_glsl_postprocess_uservec1 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec1", "0 0 0 0", "a 4-component vector to pass as uservec1 to the postprocessing shader (only useful if default.glsl has been customized)"};
186 cvar_t r_glsl_postprocess_uservec2 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec2", "0 0 0 0", "a 4-component vector to pass as uservec2 to the postprocessing shader (only useful if default.glsl has been customized)"};
187 cvar_t r_glsl_postprocess_uservec3 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec3", "0 0 0 0", "a 4-component vector to pass as uservec3 to the postprocessing shader (only useful if default.glsl has been customized)"};
188 cvar_t r_glsl_postprocess_uservec4 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec4", "0 0 0 0", "a 4-component vector to pass as uservec4 to the postprocessing shader (only useful if default.glsl has been customized)"};
189 cvar_t r_glsl_postprocess_uservec1_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec1_enable", "1", "enables postprocessing uservec1 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
190 cvar_t r_glsl_postprocess_uservec2_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec2_enable", "1", "enables postprocessing uservec2 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
191 cvar_t r_glsl_postprocess_uservec3_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec3_enable", "1", "enables postprocessing uservec3 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
192 cvar_t r_glsl_postprocess_uservec4_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec4_enable", "1", "enables postprocessing uservec4 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
193
194 cvar_t r_water = {CVAR_CLIENT | CVAR_SAVE, "r_water", "0", "whether to use reflections and refraction on water surfaces (note: r_wateralpha must be set below 1)"};
195 cvar_t r_water_cameraentitiesonly = {CVAR_CLIENT | CVAR_SAVE, "r_water_cameraentitiesonly", "0", "whether to only show QC-defined reflections/refractions (typically used for camera- or portal-like effects)"};
196 cvar_t r_water_clippingplanebias = {CVAR_CLIENT | CVAR_SAVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
197 cvar_t r_water_resolutionmultiplier = {CVAR_CLIENT | CVAR_SAVE, "r_water_resolutionmultiplier", "0.5", "multiplier for screen resolution when rendering refracted/reflected scenes, 1 is full quality, lower values are faster"};
198 cvar_t r_water_refractdistort = {CVAR_CLIENT | CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
199 cvar_t r_water_reflectdistort = {CVAR_CLIENT | CVAR_SAVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
200 cvar_t r_water_scissormode = {CVAR_CLIENT, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
201 cvar_t r_water_lowquality = {CVAR_CLIENT, "r_water_lowquality", "0", "special option to accelerate water rendering, 1 disables shadows and particles, 2 disables all dynamic lights"};
202 cvar_t r_water_hideplayer = {CVAR_CLIENT | CVAR_SAVE, "r_water_hideplayer", "0", "if set to 1 then player will be hidden in refraction views, if set to 2 then player will also be hidden in reflection views, player is always visible in camera views"};
203
204 cvar_t r_lerpsprites = {CVAR_CLIENT | CVAR_SAVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"};
205 cvar_t r_lerpmodels = {CVAR_CLIENT | CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
206 cvar_t r_lerplightstyles = {CVAR_CLIENT | CVAR_SAVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
207 cvar_t r_waterscroll = {CVAR_CLIENT | CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
208
209 cvar_t r_bloom = {CVAR_CLIENT | CVAR_SAVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
210 cvar_t r_bloom_colorscale = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorscale", "1", "how bright the glow is"};
211
212 cvar_t r_bloom_brighten = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_brighten", "2", "how bright the glow is, after subtract/power"};
213 cvar_t r_bloom_blur = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_blur", "4", "how large the glow is"};
214 cvar_t r_bloom_resolution = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
215 cvar_t r_bloom_colorexponent = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorexponent", "1", "how exaggerated the glow is"};
216 cvar_t r_bloom_colorsubtract = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorsubtract", "0.125", "reduces bloom colors by a certain amount"};
217 cvar_t r_bloom_scenebrightness = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_scenebrightness", "1", "global rendering brightness when bloom is enabled"};
218
219 cvar_t r_hdr_scenebrightness = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
220 cvar_t r_hdr_glowintensity = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
221 cvar_t r_hdr_irisadaptation = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation", "0", "adjust scene brightness according to light intensity at player location"};
222 cvar_t r_hdr_irisadaptation_multiplier = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_multiplier", "2", "brightness at which value will be 1.0"};
223 cvar_t r_hdr_irisadaptation_minvalue = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_minvalue", "0.5", "minimum value that can result from multiplier / brightness"};
224 cvar_t r_hdr_irisadaptation_maxvalue = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_maxvalue", "4", "maximum value that can result from multiplier / brightness"};
225 cvar_t r_hdr_irisadaptation_value = {CVAR_CLIENT, "r_hdr_irisadaptation_value", "1", "current value as scenebrightness multiplier, changes continuously when irisadaptation is active"};
226 cvar_t r_hdr_irisadaptation_fade_up = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_fade_up", "0.1", "fade rate at which value adjusts to darkness"};
227 cvar_t r_hdr_irisadaptation_fade_down = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_fade_down", "0.5", "fade rate at which value adjusts to brightness"};
228 cvar_t r_hdr_irisadaptation_radius = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_radius", "15", "lighting within this many units of the eye is averaged"};
229
230 cvar_t r_smoothnormals_areaweighting = {CVAR_CLIENT, "r_smoothnormals_areaweighting", "1", "uses significantly faster (and supposedly higher quality) area-weighted vertex normals and tangent vectors rather than summing normalized triangle normals and tangents"};
231
232 cvar_t developer_texturelogging = {CVAR_CLIENT, "developer_texturelogging", "0", "produces a textures.log file containing names of skins and map textures the engine tried to load"};
233
234 cvar_t gl_lightmaps = {CVAR_CLIENT, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers), a value of 2 keeps normalmap shading"};
235
236 cvar_t r_test = {CVAR_CLIENT, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
237
238 cvar_t r_batch_multidraw = {CVAR_CLIENT | CVAR_SAVE, "r_batch_multidraw", "1", "issue multiple glDrawElements calls when rendering a batch of surfaces with the same texture (otherwise the index data is copied to make it one draw)"};
239 cvar_t r_batch_multidraw_mintriangles = {CVAR_CLIENT | CVAR_SAVE, "r_batch_multidraw_mintriangles", "0", "minimum number of triangles to activate multidraw path (copying small groups of triangles may be faster)"};
240 cvar_t r_batch_debugdynamicvertexpath = {CVAR_CLIENT | CVAR_SAVE, "r_batch_debugdynamicvertexpath", "0", "force the dynamic batching code path for debugging purposes"};
241 cvar_t r_batch_dynamicbuffer = {CVAR_CLIENT | CVAR_SAVE, "r_batch_dynamicbuffer", "0", "use vertex/index buffers for drawing dynamic and copytriangles batches"};
242
243 cvar_t r_glsl_saturation = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
244 cvar_t r_glsl_saturation_redcompensate = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_saturation_redcompensate", "0", "a 'vampire sight' addition to desaturation effect, does compensation for red color, r_glsl_restart is required"};
245
246 cvar_t r_glsl_vertextextureblend_usebothalphas = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_vertextextureblend_usebothalphas", "0", "use both alpha layers on vertex blended surfaces, each alpha layer sets amount of 'blend leak' on another layer, requires mod_q3shader_force_terrain_alphaflag on."};
247
248 cvar_t r_framedatasize = {CVAR_CLIENT | CVAR_SAVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"};
249 cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
250 {
251         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"},
252         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"},
253         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"},
254         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
255 };
256
257 extern cvar_t v_glslgamma_2d;
258
259 extern qboolean v_flipped_state;
260
261 r_framebufferstate_t r_fb;
262
263 /// shadow volume bsp struct with automatically growing nodes buffer
264 svbsp_t r_svbsp;
265
266 int r_uniformbufferalignment = 32; // dynamically updated to match GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
267
268 rtexture_t *r_texture_blanknormalmap;
269 rtexture_t *r_texture_white;
270 rtexture_t *r_texture_grey128;
271 rtexture_t *r_texture_black;
272 rtexture_t *r_texture_notexture;
273 rtexture_t *r_texture_whitecube;
274 rtexture_t *r_texture_normalizationcube;
275 rtexture_t *r_texture_fogattenuation;
276 rtexture_t *r_texture_fogheighttexture;
277 rtexture_t *r_texture_gammaramps;
278 unsigned int r_texture_gammaramps_serial;
279 //rtexture_t *r_texture_fogintensity;
280 rtexture_t *r_texture_reflectcube;
281
282 // TODO: hash lookups?
283 typedef struct cubemapinfo_s
284 {
285         char basename[64];
286         rtexture_t *texture;
287 }
288 cubemapinfo_t;
289
290 int r_texture_numcubemaps;
291 cubemapinfo_t *r_texture_cubemaps[MAX_CUBEMAPS];
292
293 unsigned int r_queries[MAX_OCCLUSION_QUERIES];
294 unsigned int r_numqueries;
295 unsigned int r_maxqueries;
296
297 typedef struct r_qwskincache_s
298 {
299         char name[MAX_QPATH];
300         skinframe_t *skinframe;
301 }
302 r_qwskincache_t;
303
304 static r_qwskincache_t *r_qwskincache;
305 static int r_qwskincache_size;
306
307 /// vertex coordinates for a quad that covers the screen exactly
308 extern const float r_screenvertex3f[12];
309 const float r_screenvertex3f[12] =
310 {
311         0, 0, 0,
312         1, 0, 0,
313         1, 1, 0,
314         0, 1, 0
315 };
316
317 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
318 {
319         int i;
320         for (i = 0;i < verts;i++)
321         {
322                 out[0] = in[0] * r;
323                 out[1] = in[1] * g;
324                 out[2] = in[2] * b;
325                 out[3] = in[3];
326                 in += 4;
327                 out += 4;
328         }
329 }
330
331 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
332 {
333         int i;
334         for (i = 0;i < verts;i++)
335         {
336                 out[0] = r;
337                 out[1] = g;
338                 out[2] = b;
339                 out[3] = a;
340                 out += 4;
341         }
342 }
343
344 // FIXME: move this to client?
345 void FOG_clear(void)
346 {
347         if (gamemode == GAME_NEHAHRA)
348         {
349                 Cvar_Set(&cvars_all, "gl_fogenable", "0");
350                 Cvar_Set(&cvars_all, "gl_fogdensity", "0.2");
351                 Cvar_Set(&cvars_all, "gl_fogred", "0.3");
352                 Cvar_Set(&cvars_all, "gl_foggreen", "0.3");
353                 Cvar_Set(&cvars_all, "gl_fogblue", "0.3");
354         }
355         r_refdef.fog_density = 0;
356         r_refdef.fog_red = 0;
357         r_refdef.fog_green = 0;
358         r_refdef.fog_blue = 0;
359         r_refdef.fog_alpha = 1;
360         r_refdef.fog_start = 0;
361         r_refdef.fog_end = 16384;
362         r_refdef.fog_height = 1<<30;
363         r_refdef.fog_fadedepth = 128;
364         memset(r_refdef.fog_height_texturename, 0, sizeof(r_refdef.fog_height_texturename));
365 }
366
367 static void R_BuildBlankTextures(void)
368 {
369         unsigned char data[4];
370         data[2] = 128; // normal X
371         data[1] = 128; // normal Y
372         data[0] = 255; // normal Z
373         data[3] = 255; // height
374         r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
375         data[0] = 255;
376         data[1] = 255;
377         data[2] = 255;
378         data[3] = 255;
379         r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
380         data[0] = 128;
381         data[1] = 128;
382         data[2] = 128;
383         data[3] = 255;
384         r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
385         data[0] = 0;
386         data[1] = 0;
387         data[2] = 0;
388         data[3] = 255;
389         r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
390 }
391
392 static void R_BuildNoTexture(void)
393 {
394         int x, y;
395         unsigned char pix[16][16][4];
396         // this makes a light grey/dark grey checkerboard texture
397         for (y = 0;y < 16;y++)
398         {
399                 for (x = 0;x < 16;x++)
400                 {
401                         if ((y < 8) ^ (x < 8))
402                         {
403                                 pix[y][x][0] = 128;
404                                 pix[y][x][1] = 128;
405                                 pix[y][x][2] = 128;
406                                 pix[y][x][3] = 255;
407                         }
408                         else
409                         {
410                                 pix[y][x][0] = 64;
411                                 pix[y][x][1] = 64;
412                                 pix[y][x][2] = 64;
413                                 pix[y][x][3] = 255;
414                         }
415                 }
416         }
417         r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, -1, NULL);
418 }
419
420 static void R_BuildWhiteCube(void)
421 {
422         unsigned char data[6*1*1*4];
423         memset(data, 255, sizeof(data));
424         r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
425 }
426
427 static void R_BuildNormalizationCube(void)
428 {
429         int x, y, side;
430         vec3_t v;
431         vec_t s, t, intensity;
432 #define NORMSIZE 64
433         unsigned char *data;
434         data = (unsigned char *)Mem_Alloc(tempmempool, 6*NORMSIZE*NORMSIZE*4);
435         for (side = 0;side < 6;side++)
436         {
437                 for (y = 0;y < NORMSIZE;y++)
438                 {
439                         for (x = 0;x < NORMSIZE;x++)
440                         {
441                                 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
442                                 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
443                                 switch(side)
444                                 {
445                                 default:
446                                 case 0:
447                                         v[0] = 1;
448                                         v[1] = -t;
449                                         v[2] = -s;
450                                         break;
451                                 case 1:
452                                         v[0] = -1;
453                                         v[1] = -t;
454                                         v[2] = s;
455                                         break;
456                                 case 2:
457                                         v[0] = s;
458                                         v[1] = 1;
459                                         v[2] = t;
460                                         break;
461                                 case 3:
462                                         v[0] = s;
463                                         v[1] = -1;
464                                         v[2] = -t;
465                                         break;
466                                 case 4:
467                                         v[0] = s;
468                                         v[1] = -t;
469                                         v[2] = 1;
470                                         break;
471                                 case 5:
472                                         v[0] = -s;
473                                         v[1] = -t;
474                                         v[2] = -1;
475                                         break;
476                                 }
477                                 intensity = 127.0f / sqrt(DotProduct(v, v));
478                                 data[((side*64+y)*64+x)*4+2] = (unsigned char)(128.0f + intensity * v[0]);
479                                 data[((side*64+y)*64+x)*4+1] = (unsigned char)(128.0f + intensity * v[1]);
480                                 data[((side*64+y)*64+x)*4+0] = (unsigned char)(128.0f + intensity * v[2]);
481                                 data[((side*64+y)*64+x)*4+3] = 255;
482                         }
483                 }
484         }
485         r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
486         Mem_Free(data);
487 }
488
489 static void R_BuildFogTexture(void)
490 {
491         int x, b;
492 #define FOGWIDTH 256
493         unsigned char data1[FOGWIDTH][4];
494         //unsigned char data2[FOGWIDTH][4];
495         double d, r, alpha;
496
497         r_refdef.fogmasktable_start = r_refdef.fog_start;
498         r_refdef.fogmasktable_alpha = r_refdef.fog_alpha;
499         r_refdef.fogmasktable_range = r_refdef.fogrange;
500         r_refdef.fogmasktable_density = r_refdef.fog_density;
501
502         r = r_refdef.fogmasktable_range / FOGMASKTABLEWIDTH;
503         for (x = 0;x < FOGMASKTABLEWIDTH;x++)
504         {
505                 d = (x * r - r_refdef.fogmasktable_start);
506                 if(developer_extra.integer)
507                         Con_DPrintf("%f ", d);
508                 d = max(0, d);
509                 if (r_fog_exp2.integer)
510                         alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d);
511                 else
512                         alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d);
513                 if(developer_extra.integer)
514                         Con_DPrintf(" : %f ", alpha);
515                 alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha;
516                 if(developer_extra.integer)
517                         Con_DPrintf(" = %f\n", alpha);
518                 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
519         }
520
521         for (x = 0;x < FOGWIDTH;x++)
522         {
523                 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
524                 data1[x][0] = b;
525                 data1[x][1] = b;
526                 data1[x][2] = b;
527                 data1[x][3] = 255;
528                 //data2[x][0] = 255 - b;
529                 //data2[x][1] = 255 - b;
530                 //data2[x][2] = 255 - b;
531                 //data2[x][3] = 255;
532         }
533         if (r_texture_fogattenuation)
534         {
535                 R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
536                 //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
537         }
538         else
539         {
540                 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
541                 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
542         }
543 }
544
545 static void R_BuildFogHeightTexture(void)
546 {
547         unsigned char *inpixels;
548         int size;
549         int x;
550         int y;
551         int j;
552         float c[4];
553         float f;
554         inpixels = NULL;
555         strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename));
556         if (r_refdef.fogheighttexturename[0])
557                 inpixels = loadimagepixelsbgra(r_refdef.fogheighttexturename, true, false, false, NULL);
558         if (!inpixels)
559         {
560                 r_refdef.fog_height_tablesize = 0;
561                 if (r_texture_fogheighttexture)
562                         R_FreeTexture(r_texture_fogheighttexture);
563                 r_texture_fogheighttexture = NULL;
564                 if (r_refdef.fog_height_table2d)
565                         Mem_Free(r_refdef.fog_height_table2d);
566                 r_refdef.fog_height_table2d = NULL;
567                 if (r_refdef.fog_height_table1d)
568                         Mem_Free(r_refdef.fog_height_table1d);
569                 r_refdef.fog_height_table1d = NULL;
570                 return;
571         }
572         size = image_width;
573         r_refdef.fog_height_tablesize = size;
574         r_refdef.fog_height_table1d = (unsigned char *)Mem_Alloc(r_main_mempool, size * 4);
575         r_refdef.fog_height_table2d = (unsigned char *)Mem_Alloc(r_main_mempool, size * size * 4);
576         memcpy(r_refdef.fog_height_table1d, inpixels, size * 4);
577         Mem_Free(inpixels);
578         // LadyHavoc: now the magic - what is that table2d for?  it is a cooked
579         // average fog color table accounting for every fog layer between a point
580         // and the camera.  (Note: attenuation is handled separately!)
581         for (y = 0;y < size;y++)
582         {
583                 for (x = 0;x < size;x++)
584                 {
585                         Vector4Clear(c);
586                         f = 0;
587                         if (x < y)
588                         {
589                                 for (j = x;j <= y;j++)
590                                 {
591                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
592                                         f++;
593                                 }
594                         }
595                         else
596                         {
597                                 for (j = x;j >= y;j--)
598                                 {
599                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
600                                         f++;
601                                 }
602                         }
603                         f = 1.0f / f;
604                         r_refdef.fog_height_table2d[(y*size+x)*4+0] = (unsigned char)(c[0] * f);
605                         r_refdef.fog_height_table2d[(y*size+x)*4+1] = (unsigned char)(c[1] * f);
606                         r_refdef.fog_height_table2d[(y*size+x)*4+2] = (unsigned char)(c[2] * f);
607                         r_refdef.fog_height_table2d[(y*size+x)*4+3] = (unsigned char)(c[3] * f);
608                 }
609         }
610         r_texture_fogheighttexture = R_LoadTexture2D(r_main_texturepool, "fogheighttable", size, size, r_refdef.fog_height_table2d, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_CLAMP, -1, NULL);
611 }
612
613 //=======================================================================================================================================================
614
615 static const char *builtinshaderstrings[] =
616 {
617 #include "shader_glsl.h"
618 0
619 };
620
621 //=======================================================================================================================================================
622
623 typedef struct shaderpermutationinfo_s
624 {
625         const char *pretext;
626         const char *name;
627 }
628 shaderpermutationinfo_t;
629
630 typedef struct shadermodeinfo_s
631 {
632         const char *sourcebasename;
633         const char *extension;
634         const char **builtinshaderstrings;
635         const char *pretext;
636         const char *name;
637         char *filename;
638         char *builtinstring;
639         int builtincrc;
640 }
641 shadermodeinfo_t;
642
643 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
644 shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
645 {
646         {"#define USEDIFFUSE\n", " diffuse"},
647         {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
648         {"#define USEVIEWTINT\n", " viewtint"},
649         {"#define USECOLORMAPPING\n", " colormapping"},
650         {"#define USESATURATION\n", " saturation"},
651         {"#define USEFOGINSIDE\n", " foginside"},
652         {"#define USEFOGOUTSIDE\n", " fogoutside"},
653         {"#define USEFOGHEIGHTTEXTURE\n", " fogheighttexture"},
654         {"#define USEFOGALPHAHACK\n", " fogalphahack"},
655         {"#define USEGAMMARAMPS\n", " gammaramps"},
656         {"#define USECUBEFILTER\n", " cubefilter"},
657         {"#define USEGLOW\n", " glow"},
658         {"#define USEBLOOM\n", " bloom"},
659         {"#define USESPECULAR\n", " specular"},
660         {"#define USEPOSTPROCESSING\n", " postprocessing"},
661         {"#define USEREFLECTION\n", " reflection"},
662         {"#define USEOFFSETMAPPING\n", " offsetmapping"},
663         {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
664         {"#define USESHADOWMAP2D\n", " shadowmap2d"},
665         {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm
666         {"#define USESHADOWMAPORTHO\n", " shadowmaportho"},
667         {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
668         {"#define USEALPHAKILL\n", " alphakill"},
669         {"#define USEREFLECTCUBE\n", " reflectcube"},
670         {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"},
671         {"#define USEBOUNCEGRID\n", " bouncegrid"},
672         {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm
673         {"#define USETRIPPY\n", " trippy"},
674         {"#define USEDEPTHRGB\n", " depthrgb"},
675         {"#define USEALPHAGENVERTEX\n", " alphagenvertex"},
676         {"#define USESKELETAL\n", " skeletal"},
677         {"#define USEOCCLUDE\n", " occlude"}
678 };
679
680 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
681 shadermodeinfo_t shadermodeinfo[SHADERLANGUAGE_COUNT][SHADERMODE_COUNT] =
682 {
683         // SHADERLANGUAGE_GLSL
684         {
685                 {"combined", "glsl", builtinshaderstrings, "#define MODE_GENERIC\n", " generic"},
686                 {"combined", "glsl", builtinshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
687                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
688                 {"combined", "glsl", builtinshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
689                 {"combined", "glsl", builtinshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
690                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
691                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
692                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
693                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
694                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
695                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
696                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
697                 {"combined", "glsl", builtinshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
698                 {"combined", "glsl", builtinshaderstrings, "#define MODE_WATER\n", " water"},
699                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
700                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
701         },
702 };
703
704 struct r_glsl_permutation_s;
705 typedef struct r_glsl_permutation_s
706 {
707         /// hash lookup data
708         struct r_glsl_permutation_s *hashnext;
709         unsigned int mode;
710         dpuint64 permutation;
711
712         /// indicates if we have tried compiling this permutation already
713         qboolean compiled;
714         /// 0 if compilation failed
715         int program;
716         // texture units assigned to each detected uniform
717         int tex_Texture_First;
718         int tex_Texture_Second;
719         int tex_Texture_GammaRamps;
720         int tex_Texture_Normal;
721         int tex_Texture_Color;
722         int tex_Texture_Gloss;
723         int tex_Texture_Glow;
724         int tex_Texture_SecondaryNormal;
725         int tex_Texture_SecondaryColor;
726         int tex_Texture_SecondaryGloss;
727         int tex_Texture_SecondaryGlow;
728         int tex_Texture_Pants;
729         int tex_Texture_Shirt;
730         int tex_Texture_FogHeightTexture;
731         int tex_Texture_FogMask;
732         int tex_Texture_Lightmap;
733         int tex_Texture_Deluxemap;
734         int tex_Texture_Attenuation;
735         int tex_Texture_Cube;
736         int tex_Texture_Refraction;
737         int tex_Texture_Reflection;
738         int tex_Texture_ShadowMap2D;
739         int tex_Texture_CubeProjection;
740         int tex_Texture_ScreenNormalMap;
741         int tex_Texture_ScreenDiffuse;
742         int tex_Texture_ScreenSpecular;
743         int tex_Texture_ReflectMask;
744         int tex_Texture_ReflectCube;
745         int tex_Texture_BounceGrid;
746         /// locations of detected uniforms in program object, or -1 if not found
747         int loc_Texture_First;
748         int loc_Texture_Second;
749         int loc_Texture_GammaRamps;
750         int loc_Texture_Normal;
751         int loc_Texture_Color;
752         int loc_Texture_Gloss;
753         int loc_Texture_Glow;
754         int loc_Texture_SecondaryNormal;
755         int loc_Texture_SecondaryColor;
756         int loc_Texture_SecondaryGloss;
757         int loc_Texture_SecondaryGlow;
758         int loc_Texture_Pants;
759         int loc_Texture_Shirt;
760         int loc_Texture_FogHeightTexture;
761         int loc_Texture_FogMask;
762         int loc_Texture_Lightmap;
763         int loc_Texture_Deluxemap;
764         int loc_Texture_Attenuation;
765         int loc_Texture_Cube;
766         int loc_Texture_Refraction;
767         int loc_Texture_Reflection;
768         int loc_Texture_ShadowMap2D;
769         int loc_Texture_CubeProjection;
770         int loc_Texture_ScreenNormalMap;
771         int loc_Texture_ScreenDiffuse;
772         int loc_Texture_ScreenSpecular;
773         int loc_Texture_ReflectMask;
774         int loc_Texture_ReflectCube;
775         int loc_Texture_BounceGrid;
776         int loc_Alpha;
777         int loc_BloomBlur_Parameters;
778         int loc_ClientTime;
779         int loc_Color_Ambient;
780         int loc_Color_Diffuse;
781         int loc_Color_Specular;
782         int loc_Color_Glow;
783         int loc_Color_Pants;
784         int loc_Color_Shirt;
785         int loc_DeferredColor_Ambient;
786         int loc_DeferredColor_Diffuse;
787         int loc_DeferredColor_Specular;
788         int loc_DeferredMod_Diffuse;
789         int loc_DeferredMod_Specular;
790         int loc_DistortScaleRefractReflect;
791         int loc_EyePosition;
792         int loc_FogColor;
793         int loc_FogHeightFade;
794         int loc_FogPlane;
795         int loc_FogPlaneViewDist;
796         int loc_FogRangeRecip;
797         int loc_LightColor;
798         int loc_LightDir;
799         int loc_LightPosition;
800         int loc_OffsetMapping_ScaleSteps;
801         int loc_OffsetMapping_LodDistance;
802         int loc_OffsetMapping_Bias;
803         int loc_PixelSize;
804         int loc_ReflectColor;
805         int loc_ReflectFactor;
806         int loc_ReflectOffset;
807         int loc_RefractColor;
808         int loc_Saturation;
809         int loc_ScreenCenterRefractReflect;
810         int loc_ScreenScaleRefractReflect;
811         int loc_ScreenToDepth;
812         int loc_ShadowMap_Parameters;
813         int loc_ShadowMap_TextureScale;
814         int loc_SpecularPower;
815         int loc_Skeletal_Transform12;
816         int loc_UserVec1;
817         int loc_UserVec2;
818         int loc_UserVec3;
819         int loc_UserVec4;
820         int loc_ViewTintColor;
821         int loc_ViewToLight;
822         int loc_ModelToLight;
823         int loc_TexMatrix;
824         int loc_BackgroundTexMatrix;
825         int loc_ModelViewProjectionMatrix;
826         int loc_ModelViewMatrix;
827         int loc_PixelToScreenTexCoord;
828         int loc_ModelToReflectCube;
829         int loc_ShadowMapMatrix;
830         int loc_BloomColorSubtract;
831         int loc_NormalmapScrollBlend;
832         int loc_BounceGridMatrix;
833         int loc_BounceGridIntensity;
834         /// uniform block bindings
835         int ubibind_Skeletal_Transform12_UniformBlock;
836         /// uniform block indices
837         int ubiloc_Skeletal_Transform12_UniformBlock;
838 }
839 r_glsl_permutation_t;
840
841 #define SHADERPERMUTATION_HASHSIZE 256
842
843
844 // non-degradable "lightweight" shader parameters to keep the permutations simpler
845 // these can NOT degrade! only use for simple stuff
846 enum
847 {
848         SHADERSTATICPARM_SATURATION_REDCOMPENSATE = 0, ///< red compensation filter for saturation
849         SHADERSTATICPARM_EXACTSPECULARMATH = 1, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
850         SHADERSTATICPARM_POSTPROCESS_USERVEC1 = 2, ///< postprocess uservec1 is enabled
851         SHADERSTATICPARM_POSTPROCESS_USERVEC2 = 3, ///< postprocess uservec2 is enabled
852         SHADERSTATICPARM_POSTPROCESS_USERVEC3 = 4, ///< postprocess uservec3 is enabled
853         SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5,  ///< postprocess uservec4 is enabled
854         SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending
855         SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7,  ///< LOD for offsetmapping
856         SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1
857         SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2
858         SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
859         SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
860         SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
861         SHADERSTATICPARM_FXAA = 13 ///< fast approximate anti aliasing
862 };
863 #define SHADERSTATICPARMS_COUNT 14
864
865 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
866 static int shaderstaticparms_count = 0;
867
868 static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0};
869 #define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F))
870
871 extern qboolean r_shadow_shadowmapsampler;
872 extern int r_shadow_shadowmappcf;
873 qboolean R_CompileShader_CheckStaticParms(void)
874 {
875         static int r_compileshader_staticparms_save[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5];
876         memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
877         memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
878
879         // detect all
880         if (r_glsl_saturation_redcompensate.integer)
881                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SATURATION_REDCOMPENSATE);
882         if (r_glsl_vertextextureblend_usebothalphas.integer)
883                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS);
884         if (r_shadow_glossexact.integer)
885                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_EXACTSPECULARMATH);
886         if (r_glsl_postprocess.integer)
887         {
888                 if (r_glsl_postprocess_uservec1_enable.integer)
889                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC1);
890                 if (r_glsl_postprocess_uservec2_enable.integer)
891                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC2);
892                 if (r_glsl_postprocess_uservec3_enable.integer)
893                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC3);
894                 if (r_glsl_postprocess_uservec4_enable.integer)
895                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
896         }
897         if (r_fxaa.integer)
898                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_FXAA);
899         if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
900                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
901
902         if (r_shadow_shadowmapsampler)
903                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER);
904         if (r_shadow_shadowmappcf > 1)
905                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2);
906         else if (r_shadow_shadowmappcf)
907                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1);
908         if (r_celshading.integer)
909                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING);
910         if (r_celoutlines.integer)
911                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES);
912
913         return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
914 }
915
916 #define R_COMPILESHADER_STATICPARM_EMIT(p, n) \
917         if(r_compileshader_staticparms[(p) >> 5] & (1 << ((p) & 0x1F))) \
918                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \
919         else \
920                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n"
921 static void R_CompileShader_AddStaticParms(unsigned int mode, dpuint64 permutation)
922 {
923         shaderstaticparms_count = 0;
924
925         // emit all
926         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SATURATION_REDCOMPENSATE, "SATURATION_REDCOMPENSATE");
927         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_EXACTSPECULARMATH, "USEEXACTSPECULARMATH");
928         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC1, "USERVEC1");
929         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC2, "USERVEC2");
930         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC3, "USERVEC3");
931         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4");
932         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS");
933         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD");
934         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1");
935         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2");
936         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
937         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
938         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
939         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
940 }
941
942 /// information about each possible shader permutation
943 r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
944 /// currently selected permutation
945 r_glsl_permutation_t *r_glsl_permutation;
946 /// storage for permutations linked in the hash table
947 memexpandablearray_t r_glsl_permutationarray;
948
949 static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, dpuint64 permutation)
950 {
951         //unsigned int hashdepth = 0;
952         unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
953         r_glsl_permutation_t *p;
954         for (p = r_glsl_permutationhash[mode][hashindex];p;p = p->hashnext)
955         {
956                 if (p->mode == mode && p->permutation == permutation)
957                 {
958                         //if (hashdepth > 10)
959                         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
960                         return p;
961                 }
962                 //hashdepth++;
963         }
964         p = (r_glsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_glsl_permutationarray);
965         p->mode = mode;
966         p->permutation = permutation;
967         p->hashnext = r_glsl_permutationhash[mode][hashindex];
968         r_glsl_permutationhash[mode][hashindex] = p;
969         //if (hashdepth > 10)
970         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
971         return p;
972 }
973
974 static char *R_ShaderStrCat(const char **strings)
975 {
976         char *string, *s;
977         const char **p = strings;
978         const char *t;
979         size_t len = 0;
980         for (p = strings;(t = *p);p++)
981                 len += strlen(t);
982         len++;
983         s = string = (char *)Mem_Alloc(r_main_mempool, len);
984         len = 0;
985         for (p = strings;(t = *p);p++)
986         {
987                 len = strlen(t);
988                 memcpy(s, t, len);
989                 s += len;
990         }
991         *s = 0;
992         return string;
993 }
994
995 static char *R_ShaderStrCat(const char **strings);
996 static void R_InitShaderModeInfo(void)
997 {
998         int i, language;
999         shadermodeinfo_t *modeinfo;
1000         // we have a bunch of things to compute that weren't calculated at engine compile time - all filenames should have a crc of the builtin strings to prevent accidental overrides (any customization must be updated to match engine)
1001         for (language = 0; language < SHADERLANGUAGE_COUNT; language++)
1002         {
1003                 for (i = 0; i < SHADERMODE_COUNT; i++)
1004                 {
1005                         char filename[MAX_QPATH];
1006                         modeinfo = &shadermodeinfo[language][i];
1007                         modeinfo->builtinstring = R_ShaderStrCat(modeinfo->builtinshaderstrings);
1008                         modeinfo->builtincrc = CRC_Block((const unsigned char *)modeinfo->builtinstring, strlen(modeinfo->builtinstring));
1009                         dpsnprintf(filename, sizeof(filename), "%s/%s_crc%i.%s", modeinfo->extension, modeinfo->sourcebasename, modeinfo->builtincrc, modeinfo->extension);
1010                         modeinfo->filename = Mem_strdup(r_main_mempool, filename);
1011                 }
1012         }
1013 }
1014
1015 static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qboolean printfromdisknotice, qboolean builtinonly)
1016 {
1017         char *shaderstring;
1018         // if the mode has no filename we have to return the builtin string
1019         if (builtinonly || !modeinfo->filename)
1020                 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1021         // note that FS_LoadFile appends a 0 byte to make it a valid string
1022         shaderstring = (char *)FS_LoadFile(modeinfo->filename, r_main_mempool, false, NULL);
1023         if (shaderstring)
1024         {
1025                 if (printfromdisknotice)
1026                         Con_DPrintf("Loading shaders from file %s...\n", modeinfo->filename);
1027                 return shaderstring;
1028         }
1029         // fall back to builtinstring
1030         return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1031 }
1032
1033 static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, dpuint64 permutation)
1034 {
1035         int i;
1036         int ubibind;
1037         int sampler;
1038         shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode];
1039         char *sourcestring;
1040         char permutationname[256];
1041         int vertstrings_count = 0;
1042         int geomstrings_count = 0;
1043         int fragstrings_count = 0;
1044         const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1045         const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1046         const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1047
1048         if (p->compiled)
1049                 return;
1050         p->compiled = true;
1051         p->program = 0;
1052
1053         permutationname[0] = 0;
1054         sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false);
1055
1056         strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
1057
1058         // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object)
1059         if(vid.support.glshaderversion >= 140)
1060         {
1061                 vertstrings_list[vertstrings_count++] = "#version 140\n";
1062                 geomstrings_list[geomstrings_count++] = "#version 140\n";
1063                 fragstrings_list[fragstrings_count++] = "#version 140\n";
1064                 vertstrings_list[vertstrings_count++] = "#define GLSL140\n";
1065                 geomstrings_list[geomstrings_count++] = "#define GLSL140\n";
1066                 fragstrings_list[fragstrings_count++] = "#define GLSL140\n";
1067         }
1068         // if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad)
1069         else if(vid.support.glshaderversion >= 130)
1070         {
1071                 vertstrings_list[vertstrings_count++] = "#version 130\n";
1072                 geomstrings_list[geomstrings_count++] = "#version 130\n";
1073                 fragstrings_list[fragstrings_count++] = "#version 130\n";
1074                 vertstrings_list[vertstrings_count++] = "#define GLSL130\n";
1075                 geomstrings_list[geomstrings_count++] = "#define GLSL130\n";
1076                 fragstrings_list[fragstrings_count++] = "#define GLSL130\n";
1077         }
1078         // if we can do #version 120, we should (this adds the invariant keyword)
1079         else if(vid.support.glshaderversion >= 120)
1080         {
1081                 vertstrings_list[vertstrings_count++] = "#version 120\n";
1082                 geomstrings_list[geomstrings_count++] = "#version 120\n";
1083                 fragstrings_list[fragstrings_count++] = "#version 120\n";
1084                 vertstrings_list[vertstrings_count++] = "#define GLSL120\n";
1085                 geomstrings_list[geomstrings_count++] = "#define GLSL120\n";
1086                 fragstrings_list[fragstrings_count++] = "#define GLSL120\n";
1087         }
1088         // GLES also adds several things from GLSL120
1089         switch(vid.renderpath)
1090         {
1091         case RENDERPATH_GLES2:
1092                 vertstrings_list[vertstrings_count++] = "#define GLES\n";
1093                 geomstrings_list[geomstrings_count++] = "#define GLES\n";
1094                 fragstrings_list[fragstrings_count++] = "#define GLES\n";
1095                 break;
1096         default:
1097                 break;
1098         }
1099
1100         // the first pretext is which type of shader to compile as
1101         // (later these will all be bound together as a program object)
1102         vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
1103         geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
1104         fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
1105
1106         // the second pretext is the mode (for example a light source)
1107         vertstrings_list[vertstrings_count++] = modeinfo->pretext;
1108         geomstrings_list[geomstrings_count++] = modeinfo->pretext;
1109         fragstrings_list[fragstrings_count++] = modeinfo->pretext;
1110         strlcat(permutationname, modeinfo->name, sizeof(permutationname));
1111
1112         // now add all the permutation pretexts
1113         for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1114         {
1115                 if (permutation & (1ll<<i))
1116                 {
1117                         vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
1118                         geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
1119                         fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
1120                         strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
1121                 }
1122                 else
1123                 {
1124                         // keep line numbers correct
1125                         vertstrings_list[vertstrings_count++] = "\n";
1126                         geomstrings_list[geomstrings_count++] = "\n";
1127                         fragstrings_list[fragstrings_count++] = "\n";
1128                 }
1129         }
1130
1131         // add static parms
1132         R_CompileShader_AddStaticParms(mode, permutation);
1133         memcpy((char *)(vertstrings_list + vertstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1134         vertstrings_count += shaderstaticparms_count;
1135         memcpy((char *)(geomstrings_list + geomstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1136         geomstrings_count += shaderstaticparms_count;
1137         memcpy((char *)(fragstrings_list + fragstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1138         fragstrings_count += shaderstaticparms_count;
1139
1140         // now append the shader text itself
1141         vertstrings_list[vertstrings_count++] = sourcestring;
1142         geomstrings_list[geomstrings_count++] = sourcestring;
1143         fragstrings_list[fragstrings_count++] = sourcestring;
1144
1145         // we don't currently use geometry shaders for anything, so just empty the list
1146         geomstrings_count = 0;
1147
1148         // compile the shader program
1149         if (vertstrings_count + geomstrings_count + fragstrings_count)
1150                 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1151         if (p->program)
1152         {
1153                 CHECKGLERROR
1154                 qglUseProgram(p->program);CHECKGLERROR
1155                 // look up all the uniform variable names we care about, so we don't
1156                 // have to look them up every time we set them
1157
1158 #if 0
1159                 // debugging aid
1160                 {
1161                         GLint activeuniformindex = 0;
1162                         GLint numactiveuniforms = 0;
1163                         char uniformname[128];
1164                         GLsizei uniformnamelength = 0;
1165                         GLint uniformsize = 0;
1166                         GLenum uniformtype = 0;
1167                         memset(uniformname, 0, sizeof(uniformname));
1168                         qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms);
1169                         Con_Printf("Shader has %i uniforms\n", numactiveuniforms);
1170                         for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++)
1171                         {
1172                                 qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname);
1173                                 Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype);
1174                         }
1175                 }
1176 #endif
1177
1178                 p->loc_Texture_First              = qglGetUniformLocation(p->program, "Texture_First");
1179                 p->loc_Texture_Second             = qglGetUniformLocation(p->program, "Texture_Second");
1180                 p->loc_Texture_GammaRamps         = qglGetUniformLocation(p->program, "Texture_GammaRamps");
1181                 p->loc_Texture_Normal             = qglGetUniformLocation(p->program, "Texture_Normal");
1182                 p->loc_Texture_Color              = qglGetUniformLocation(p->program, "Texture_Color");
1183                 p->loc_Texture_Gloss              = qglGetUniformLocation(p->program, "Texture_Gloss");
1184                 p->loc_Texture_Glow               = qglGetUniformLocation(p->program, "Texture_Glow");
1185                 p->loc_Texture_SecondaryNormal    = qglGetUniformLocation(p->program, "Texture_SecondaryNormal");
1186                 p->loc_Texture_SecondaryColor     = qglGetUniformLocation(p->program, "Texture_SecondaryColor");
1187                 p->loc_Texture_SecondaryGloss     = qglGetUniformLocation(p->program, "Texture_SecondaryGloss");
1188                 p->loc_Texture_SecondaryGlow      = qglGetUniformLocation(p->program, "Texture_SecondaryGlow");
1189                 p->loc_Texture_Pants              = qglGetUniformLocation(p->program, "Texture_Pants");
1190                 p->loc_Texture_Shirt              = qglGetUniformLocation(p->program, "Texture_Shirt");
1191                 p->loc_Texture_FogHeightTexture   = qglGetUniformLocation(p->program, "Texture_FogHeightTexture");
1192                 p->loc_Texture_FogMask            = qglGetUniformLocation(p->program, "Texture_FogMask");
1193                 p->loc_Texture_Lightmap           = qglGetUniformLocation(p->program, "Texture_Lightmap");
1194                 p->loc_Texture_Deluxemap          = qglGetUniformLocation(p->program, "Texture_Deluxemap");
1195                 p->loc_Texture_Attenuation        = qglGetUniformLocation(p->program, "Texture_Attenuation");
1196                 p->loc_Texture_Cube               = qglGetUniformLocation(p->program, "Texture_Cube");
1197                 p->loc_Texture_Refraction         = qglGetUniformLocation(p->program, "Texture_Refraction");
1198                 p->loc_Texture_Reflection         = qglGetUniformLocation(p->program, "Texture_Reflection");
1199                 p->loc_Texture_ShadowMap2D        = qglGetUniformLocation(p->program, "Texture_ShadowMap2D");
1200                 p->loc_Texture_CubeProjection     = qglGetUniformLocation(p->program, "Texture_CubeProjection");
1201                 p->loc_Texture_ScreenNormalMap    = qglGetUniformLocation(p->program, "Texture_ScreenNormalMap");
1202                 p->loc_Texture_ScreenDiffuse      = qglGetUniformLocation(p->program, "Texture_ScreenDiffuse");
1203                 p->loc_Texture_ScreenSpecular     = qglGetUniformLocation(p->program, "Texture_ScreenSpecular");
1204                 p->loc_Texture_ReflectMask        = qglGetUniformLocation(p->program, "Texture_ReflectMask");
1205                 p->loc_Texture_ReflectCube        = qglGetUniformLocation(p->program, "Texture_ReflectCube");
1206                 p->loc_Texture_BounceGrid         = qglGetUniformLocation(p->program, "Texture_BounceGrid");
1207                 p->loc_Alpha                      = qglGetUniformLocation(p->program, "Alpha");
1208                 p->loc_BloomBlur_Parameters       = qglGetUniformLocation(p->program, "BloomBlur_Parameters");
1209                 p->loc_ClientTime                 = qglGetUniformLocation(p->program, "ClientTime");
1210                 p->loc_Color_Ambient              = qglGetUniformLocation(p->program, "Color_Ambient");
1211                 p->loc_Color_Diffuse              = qglGetUniformLocation(p->program, "Color_Diffuse");
1212                 p->loc_Color_Specular             = qglGetUniformLocation(p->program, "Color_Specular");
1213                 p->loc_Color_Glow                 = qglGetUniformLocation(p->program, "Color_Glow");
1214                 p->loc_Color_Pants                = qglGetUniformLocation(p->program, "Color_Pants");
1215                 p->loc_Color_Shirt                = qglGetUniformLocation(p->program, "Color_Shirt");
1216                 p->loc_DeferredColor_Ambient      = qglGetUniformLocation(p->program, "DeferredColor_Ambient");
1217                 p->loc_DeferredColor_Diffuse      = qglGetUniformLocation(p->program, "DeferredColor_Diffuse");
1218                 p->loc_DeferredColor_Specular     = qglGetUniformLocation(p->program, "DeferredColor_Specular");
1219                 p->loc_DeferredMod_Diffuse        = qglGetUniformLocation(p->program, "DeferredMod_Diffuse");
1220                 p->loc_DeferredMod_Specular       = qglGetUniformLocation(p->program, "DeferredMod_Specular");
1221                 p->loc_DistortScaleRefractReflect = qglGetUniformLocation(p->program, "DistortScaleRefractReflect");
1222                 p->loc_EyePosition                = qglGetUniformLocation(p->program, "EyePosition");
1223                 p->loc_FogColor                   = qglGetUniformLocation(p->program, "FogColor");
1224                 p->loc_FogHeightFade              = qglGetUniformLocation(p->program, "FogHeightFade");
1225                 p->loc_FogPlane                   = qglGetUniformLocation(p->program, "FogPlane");
1226                 p->loc_FogPlaneViewDist           = qglGetUniformLocation(p->program, "FogPlaneViewDist");
1227                 p->loc_FogRangeRecip              = qglGetUniformLocation(p->program, "FogRangeRecip");
1228                 p->loc_LightColor                 = qglGetUniformLocation(p->program, "LightColor");
1229                 p->loc_LightDir                   = qglGetUniformLocation(p->program, "LightDir");
1230                 p->loc_LightPosition              = qglGetUniformLocation(p->program, "LightPosition");
1231                 p->loc_OffsetMapping_ScaleSteps   = qglGetUniformLocation(p->program, "OffsetMapping_ScaleSteps");
1232                 p->loc_OffsetMapping_LodDistance  = qglGetUniformLocation(p->program, "OffsetMapping_LodDistance");
1233                 p->loc_OffsetMapping_Bias         = qglGetUniformLocation(p->program, "OffsetMapping_Bias");
1234                 p->loc_PixelSize                  = qglGetUniformLocation(p->program, "PixelSize");
1235                 p->loc_ReflectColor               = qglGetUniformLocation(p->program, "ReflectColor");
1236                 p->loc_ReflectFactor              = qglGetUniformLocation(p->program, "ReflectFactor");
1237                 p->loc_ReflectOffset              = qglGetUniformLocation(p->program, "ReflectOffset");
1238                 p->loc_RefractColor               = qglGetUniformLocation(p->program, "RefractColor");
1239                 p->loc_Saturation                 = qglGetUniformLocation(p->program, "Saturation");
1240                 p->loc_ScreenCenterRefractReflect = qglGetUniformLocation(p->program, "ScreenCenterRefractReflect");
1241                 p->loc_ScreenScaleRefractReflect  = qglGetUniformLocation(p->program, "ScreenScaleRefractReflect");
1242                 p->loc_ScreenToDepth              = qglGetUniformLocation(p->program, "ScreenToDepth");
1243                 p->loc_ShadowMap_Parameters       = qglGetUniformLocation(p->program, "ShadowMap_Parameters");
1244                 p->loc_ShadowMap_TextureScale     = qglGetUniformLocation(p->program, "ShadowMap_TextureScale");
1245                 p->loc_SpecularPower              = qglGetUniformLocation(p->program, "SpecularPower");
1246                 p->loc_UserVec1                   = qglGetUniformLocation(p->program, "UserVec1");
1247                 p->loc_UserVec2                   = qglGetUniformLocation(p->program, "UserVec2");
1248                 p->loc_UserVec3                   = qglGetUniformLocation(p->program, "UserVec3");
1249                 p->loc_UserVec4                   = qglGetUniformLocation(p->program, "UserVec4");
1250                 p->loc_ViewTintColor              = qglGetUniformLocation(p->program, "ViewTintColor");
1251                 p->loc_ViewToLight                = qglGetUniformLocation(p->program, "ViewToLight");
1252                 p->loc_ModelToLight               = qglGetUniformLocation(p->program, "ModelToLight");
1253                 p->loc_TexMatrix                  = qglGetUniformLocation(p->program, "TexMatrix");
1254                 p->loc_BackgroundTexMatrix        = qglGetUniformLocation(p->program, "BackgroundTexMatrix");
1255                 p->loc_ModelViewMatrix            = qglGetUniformLocation(p->program, "ModelViewMatrix");
1256                 p->loc_ModelViewProjectionMatrix  = qglGetUniformLocation(p->program, "ModelViewProjectionMatrix");
1257                 p->loc_PixelToScreenTexCoord      = qglGetUniformLocation(p->program, "PixelToScreenTexCoord");
1258                 p->loc_ModelToReflectCube         = qglGetUniformLocation(p->program, "ModelToReflectCube");
1259                 p->loc_ShadowMapMatrix            = qglGetUniformLocation(p->program, "ShadowMapMatrix");
1260                 p->loc_BloomColorSubtract         = qglGetUniformLocation(p->program, "BloomColorSubtract");
1261                 p->loc_NormalmapScrollBlend       = qglGetUniformLocation(p->program, "NormalmapScrollBlend");
1262                 p->loc_BounceGridMatrix           = qglGetUniformLocation(p->program, "BounceGridMatrix");
1263                 p->loc_BounceGridIntensity        = qglGetUniformLocation(p->program, "BounceGridIntensity");
1264                 // initialize the samplers to refer to the texture units we use
1265                 p->tex_Texture_First = -1;
1266                 p->tex_Texture_Second = -1;
1267                 p->tex_Texture_GammaRamps = -1;
1268                 p->tex_Texture_Normal = -1;
1269                 p->tex_Texture_Color = -1;
1270                 p->tex_Texture_Gloss = -1;
1271                 p->tex_Texture_Glow = -1;
1272                 p->tex_Texture_SecondaryNormal = -1;
1273                 p->tex_Texture_SecondaryColor = -1;
1274                 p->tex_Texture_SecondaryGloss = -1;
1275                 p->tex_Texture_SecondaryGlow = -1;
1276                 p->tex_Texture_Pants = -1;
1277                 p->tex_Texture_Shirt = -1;
1278                 p->tex_Texture_FogHeightTexture = -1;
1279                 p->tex_Texture_FogMask = -1;
1280                 p->tex_Texture_Lightmap = -1;
1281                 p->tex_Texture_Deluxemap = -1;
1282                 p->tex_Texture_Attenuation = -1;
1283                 p->tex_Texture_Cube = -1;
1284                 p->tex_Texture_Refraction = -1;
1285                 p->tex_Texture_Reflection = -1;
1286                 p->tex_Texture_ShadowMap2D = -1;
1287                 p->tex_Texture_CubeProjection = -1;
1288                 p->tex_Texture_ScreenNormalMap = -1;
1289                 p->tex_Texture_ScreenDiffuse = -1;
1290                 p->tex_Texture_ScreenSpecular = -1;
1291                 p->tex_Texture_ReflectMask = -1;
1292                 p->tex_Texture_ReflectCube = -1;
1293                 p->tex_Texture_BounceGrid = -1;
1294                 // bind the texture samplers in use
1295                 sampler = 0;
1296                 if (p->loc_Texture_First           >= 0) {p->tex_Texture_First            = sampler;qglUniform1i(p->loc_Texture_First           , sampler);sampler++;}
1297                 if (p->loc_Texture_Second          >= 0) {p->tex_Texture_Second           = sampler;qglUniform1i(p->loc_Texture_Second          , sampler);sampler++;}
1298                 if (p->loc_Texture_GammaRamps      >= 0) {p->tex_Texture_GammaRamps       = sampler;qglUniform1i(p->loc_Texture_GammaRamps      , sampler);sampler++;}
1299                 if (p->loc_Texture_Normal          >= 0) {p->tex_Texture_Normal           = sampler;qglUniform1i(p->loc_Texture_Normal          , sampler);sampler++;}
1300                 if (p->loc_Texture_Color           >= 0) {p->tex_Texture_Color            = sampler;qglUniform1i(p->loc_Texture_Color           , sampler);sampler++;}
1301                 if (p->loc_Texture_Gloss           >= 0) {p->tex_Texture_Gloss            = sampler;qglUniform1i(p->loc_Texture_Gloss           , sampler);sampler++;}
1302                 if (p->loc_Texture_Glow            >= 0) {p->tex_Texture_Glow             = sampler;qglUniform1i(p->loc_Texture_Glow            , sampler);sampler++;}
1303                 if (p->loc_Texture_SecondaryNormal >= 0) {p->tex_Texture_SecondaryNormal  = sampler;qglUniform1i(p->loc_Texture_SecondaryNormal , sampler);sampler++;}
1304                 if (p->loc_Texture_SecondaryColor  >= 0) {p->tex_Texture_SecondaryColor   = sampler;qglUniform1i(p->loc_Texture_SecondaryColor  , sampler);sampler++;}
1305                 if (p->loc_Texture_SecondaryGloss  >= 0) {p->tex_Texture_SecondaryGloss   = sampler;qglUniform1i(p->loc_Texture_SecondaryGloss  , sampler);sampler++;}
1306                 if (p->loc_Texture_SecondaryGlow   >= 0) {p->tex_Texture_SecondaryGlow    = sampler;qglUniform1i(p->loc_Texture_SecondaryGlow   , sampler);sampler++;}
1307                 if (p->loc_Texture_Pants           >= 0) {p->tex_Texture_Pants            = sampler;qglUniform1i(p->loc_Texture_Pants           , sampler);sampler++;}
1308                 if (p->loc_Texture_Shirt           >= 0) {p->tex_Texture_Shirt            = sampler;qglUniform1i(p->loc_Texture_Shirt           , sampler);sampler++;}
1309                 if (p->loc_Texture_FogHeightTexture>= 0) {p->tex_Texture_FogHeightTexture = sampler;qglUniform1i(p->loc_Texture_FogHeightTexture, sampler);sampler++;}
1310                 if (p->loc_Texture_FogMask         >= 0) {p->tex_Texture_FogMask          = sampler;qglUniform1i(p->loc_Texture_FogMask         , sampler);sampler++;}
1311                 if (p->loc_Texture_Lightmap        >= 0) {p->tex_Texture_Lightmap         = sampler;qglUniform1i(p->loc_Texture_Lightmap        , sampler);sampler++;}
1312                 if (p->loc_Texture_Deluxemap       >= 0) {p->tex_Texture_Deluxemap        = sampler;qglUniform1i(p->loc_Texture_Deluxemap       , sampler);sampler++;}
1313                 if (p->loc_Texture_Attenuation     >= 0) {p->tex_Texture_Attenuation      = sampler;qglUniform1i(p->loc_Texture_Attenuation     , sampler);sampler++;}
1314                 if (p->loc_Texture_Cube            >= 0) {p->tex_Texture_Cube             = sampler;qglUniform1i(p->loc_Texture_Cube            , sampler);sampler++;}
1315                 if (p->loc_Texture_Refraction      >= 0) {p->tex_Texture_Refraction       = sampler;qglUniform1i(p->loc_Texture_Refraction      , sampler);sampler++;}
1316                 if (p->loc_Texture_Reflection      >= 0) {p->tex_Texture_Reflection       = sampler;qglUniform1i(p->loc_Texture_Reflection      , sampler);sampler++;}
1317                 if (p->loc_Texture_ShadowMap2D     >= 0) {p->tex_Texture_ShadowMap2D      = sampler;qglUniform1i(p->loc_Texture_ShadowMap2D     , sampler);sampler++;}
1318                 if (p->loc_Texture_CubeProjection  >= 0) {p->tex_Texture_CubeProjection   = sampler;qglUniform1i(p->loc_Texture_CubeProjection  , sampler);sampler++;}
1319                 if (p->loc_Texture_ScreenNormalMap >= 0) {p->tex_Texture_ScreenNormalMap  = sampler;qglUniform1i(p->loc_Texture_ScreenNormalMap , sampler);sampler++;}
1320                 if (p->loc_Texture_ScreenDiffuse   >= 0) {p->tex_Texture_ScreenDiffuse    = sampler;qglUniform1i(p->loc_Texture_ScreenDiffuse   , sampler);sampler++;}
1321                 if (p->loc_Texture_ScreenSpecular  >= 0) {p->tex_Texture_ScreenSpecular   = sampler;qglUniform1i(p->loc_Texture_ScreenSpecular  , sampler);sampler++;}
1322                 if (p->loc_Texture_ReflectMask     >= 0) {p->tex_Texture_ReflectMask      = sampler;qglUniform1i(p->loc_Texture_ReflectMask     , sampler);sampler++;}
1323                 if (p->loc_Texture_ReflectCube     >= 0) {p->tex_Texture_ReflectCube      = sampler;qglUniform1i(p->loc_Texture_ReflectCube     , sampler);sampler++;}
1324                 if (p->loc_Texture_BounceGrid      >= 0) {p->tex_Texture_BounceGrid       = sampler;qglUniform1i(p->loc_Texture_BounceGrid      , sampler);sampler++;}
1325                 // get the uniform block indices so we can bind them
1326                 p->ubiloc_Skeletal_Transform12_UniformBlock = -1;
1327 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1328                 p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
1329 #endif
1330                 // clear the uniform block bindings
1331                 p->ubibind_Skeletal_Transform12_UniformBlock = -1;
1332                 // bind the uniform blocks in use
1333                 ubibind = 0;
1334 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1335                 if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;}
1336 #endif
1337                 // we're done compiling and setting up the shader, at least until it is used
1338                 CHECKGLERROR
1339                 Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler);
1340         }
1341         else
1342                 Con_Printf("^1GLSL shader %s failed!  some features may not work properly.\n", permutationname);
1343
1344         // free the strings
1345         if (sourcestring)
1346                 Mem_Free(sourcestring);
1347 }
1348
1349 static void R_SetupShader_SetPermutationGLSL(unsigned int mode, dpuint64 permutation)
1350 {
1351         r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation);
1352         if (r_glsl_permutation != perm)
1353         {
1354                 r_glsl_permutation = perm;
1355                 if (!r_glsl_permutation->program)
1356                 {
1357                         if (!r_glsl_permutation->compiled)
1358                         {
1359                                 Con_DPrintf("Compiling shader mode %u permutation %llx\n", mode, permutation);
1360                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1361                         }
1362                         if (!r_glsl_permutation->program)
1363                         {
1364                                 // remove features until we find a valid permutation
1365                                 int i;
1366                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1367                                 {
1368                                         // reduce i more quickly whenever it would not remove any bits
1369                                         dpuint64 j = 1ll<<(SHADERPERMUTATION_COUNT-1-i);
1370                                         if (!(permutation & j))
1371                                                 continue;
1372                                         permutation -= j;
1373                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1374                                         if (!r_glsl_permutation->compiled)
1375                                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1376                                         if (r_glsl_permutation->program)
1377                                                 break;
1378                                 }
1379                                 if (i >= SHADERPERMUTATION_COUNT)
1380                                 {
1381                                         //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext);
1382                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1383                                         qglUseProgram(0);CHECKGLERROR
1384                                         return; // no bit left to clear, entire mode is broken
1385                                 }
1386                         }
1387                 }
1388                 CHECKGLERROR
1389                 qglUseProgram(r_glsl_permutation->program);CHECKGLERROR
1390         }
1391         if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
1392         if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
1393         if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time);
1394         CHECKGLERROR
1395 }
1396
1397 void R_GLSL_Restart_f(cmd_state_t *cmd)
1398 {
1399         unsigned int i, limit;
1400         switch(vid.renderpath)
1401         {
1402         case RENDERPATH_GL32:
1403         case RENDERPATH_GLES2:
1404                 {
1405                         r_glsl_permutation_t *p;
1406                         r_glsl_permutation = NULL;
1407                         limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
1408                         for (i = 0;i < limit;i++)
1409                         {
1410                                 if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
1411                                 {
1412                                         GL_Backend_FreeProgram(p->program);
1413                                         Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
1414                                 }
1415                         }
1416                         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
1417                 }
1418                 break;
1419         }
1420 }
1421
1422 static void R_GLSL_DumpShader_f(cmd_state_t *cmd)
1423 {
1424         int i, language, mode, dupe;
1425         char *text;
1426         shadermodeinfo_t *modeinfo;
1427         qfile_t *file;
1428
1429         for (language = 0;language < SHADERLANGUAGE_COUNT;language++)
1430         {
1431                 modeinfo = shadermodeinfo[language];
1432                 for (mode = 0;mode < SHADERMODE_COUNT;mode++)
1433                 {
1434                         // don't dump the same file multiple times (most or all shaders come from the same file)
1435                         for (dupe = mode - 1;dupe >= 0;dupe--)
1436                                 if (!strcmp(modeinfo[mode].filename, modeinfo[dupe].filename))
1437                                         break;
1438                         if (dupe >= 0)
1439                                 continue;
1440                         text = modeinfo[mode].builtinstring;
1441                         if (!text)
1442                                 continue;
1443                         file = FS_OpenRealFile(modeinfo[mode].filename, "w", false);
1444                         if (file)
1445                         {
1446                                 FS_Print(file, "/* The engine may define the following macros:\n");
1447                                 FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
1448                                 for (i = 0;i < SHADERMODE_COUNT;i++)
1449                                         FS_Print(file, modeinfo[i].pretext);
1450                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1451                                         FS_Print(file, shaderpermutationinfo[i].pretext);
1452                                 FS_Print(file, "*/\n");
1453                                 FS_Print(file, text);
1454                                 FS_Close(file);
1455                                 Con_Printf("%s written\n", modeinfo[mode].filename);
1456                         }
1457                         else
1458                                 Con_Printf("failed to write to %s\n", modeinfo[mode].filename);
1459                 }
1460         }
1461 }
1462
1463 void R_SetupShader_Generic(rtexture_t *t, qboolean usegamma, qboolean notrippy, qboolean suppresstexalpha)
1464 {
1465         dpuint64 permutation = 0;
1466         if (r_trippy.integer && !notrippy)
1467                 permutation |= SHADERPERMUTATION_TRIPPY;
1468         permutation |= SHADERPERMUTATION_VIEWTINT;
1469         if (t)
1470                 permutation |= SHADERPERMUTATION_DIFFUSE;
1471         if (usegamma && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
1472                 permutation |= SHADERPERMUTATION_GAMMARAMPS;
1473         if (suppresstexalpha)
1474                 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1475         if (vid.allowalphatocoverage)
1476                 GL_AlphaToCoverage(false);
1477         switch (vid.renderpath)
1478         {
1479         case RENDERPATH_GL32:
1480         case RENDERPATH_GLES2:
1481                 R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation);
1482                 if (r_glsl_permutation->tex_Texture_First >= 0)
1483                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First, t);
1484                 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0)
1485                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps);
1486                 break;
1487         }
1488 }
1489
1490 void R_SetupShader_Generic_NoTexture(qboolean usegamma, qboolean notrippy)
1491 {
1492         R_SetupShader_Generic(NULL, usegamma, notrippy, false);
1493 }
1494
1495 void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb, qboolean skeletal)
1496 {
1497         dpuint64 permutation = 0;
1498         if (r_trippy.integer && !notrippy)
1499                 permutation |= SHADERPERMUTATION_TRIPPY;
1500         if (depthrgb)
1501                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1502         if (skeletal)
1503                 permutation |= SHADERPERMUTATION_SKELETAL;
1504
1505         if (vid.allowalphatocoverage)
1506                 GL_AlphaToCoverage(false);
1507         switch (vid.renderpath)
1508         {
1509         case RENDERPATH_GL32:
1510         case RENDERPATH_GLES2:
1511                 R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
1512 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1513                 if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
1514 #endif
1515                 break;
1516         }
1517 }
1518
1519 #define BLENDFUNC_ALLOWS_COLORMOD      1
1520 #define BLENDFUNC_ALLOWS_FOG           2
1521 #define BLENDFUNC_ALLOWS_FOG_HACK0     4
1522 #define BLENDFUNC_ALLOWS_FOG_HACKALPHA 8
1523 #define BLENDFUNC_ALLOWS_ANYFOG        (BLENDFUNC_ALLOWS_FOG | BLENDFUNC_ALLOWS_FOG_HACK0 | BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1524 static int R_BlendFuncFlags(int src, int dst)
1525 {
1526         int r = 0;
1527
1528         // a blendfunc allows colormod if:
1529         // a) it can never keep the destination pixel invariant, or
1530         // b) it can keep the destination pixel invariant, and still can do so if colormodded
1531         // this is to prevent unintended side effects from colormod
1532
1533         // a blendfunc allows fog if:
1534         // blend(fog(src), fog(dst)) == fog(blend(src, dst))
1535         // this is to prevent unintended side effects from fog
1536
1537         // these checks are the output of fogeval.pl
1538
1539         r |= BLENDFUNC_ALLOWS_COLORMOD;
1540         if(src == GL_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1541         if(src == GL_DST_ALPHA && dst == GL_ONE_MINUS_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1542         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1543         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1544         if(src == GL_DST_COLOR && dst == GL_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1545         if(src == GL_DST_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1546         if(src == GL_DST_COLOR && dst == GL_ZERO) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1547         if(src == GL_ONE && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1548         if(src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG_HACKALPHA;
1549         if(src == GL_ONE && dst == GL_ZERO) r |= BLENDFUNC_ALLOWS_FOG;
1550         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1551         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1552         if(src == GL_ONE_MINUS_DST_COLOR && dst == GL_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1553         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1554         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1555         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1556         if(src == GL_ONE_MINUS_SRC_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1557         if(src == GL_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1558         if(src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1559         if(src == GL_ZERO && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG;
1560         if(src == GL_ZERO && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1561
1562         return r;
1563 }
1564
1565 void R_SetupShader_Surface(const float rtlightambient[3], const float rtlightdiffuse[3], const float rtlightspecular[3], rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist, void *surfacewaterplane, qboolean notrippy)
1566 {
1567         // select a permutation of the lighting shader appropriate to this
1568         // combination of texture, entity, light source, and fogging, only use the
1569         // minimum features necessary to avoid wasting rendering time in the
1570         // fragment shader on features that are not being used
1571         dpuint64 permutation = 0;
1572         unsigned int mode = 0;
1573         int blendfuncflags;
1574         texture_t *t = rsurface.texture;
1575         float m16f[16];
1576         matrix4x4_t tempmatrix;
1577         r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
1578         if (r_trippy.integer && !notrippy)
1579                 permutation |= SHADERPERMUTATION_TRIPPY;
1580         if (t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1581                 permutation |= SHADERPERMUTATION_ALPHAKILL;
1582         if (t->currentmaterialflags & MATERIALFLAG_OCCLUDE)
1583                 permutation |= SHADERPERMUTATION_OCCLUDE;
1584         if (t->r_water_waterscroll[0] && t->r_water_waterscroll[1])
1585                 permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
1586         if (rsurfacepass == RSURFPASS_BACKGROUND)
1587         {
1588                 // distorted background
1589                 if (t->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1590                 {
1591                         mode = SHADERMODE_WATER;
1592                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1593                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1594                         if((r_wateralpha.value < 1) && (t->currentmaterialflags & MATERIALFLAG_WATERALPHA))
1595                         {
1596                                 // this is the right thing to do for wateralpha
1597                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1598                                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1599                         }
1600                         else
1601                         {
1602                                 // this is the right thing to do for entity alpha
1603                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1604                                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1605                         }
1606                 }
1607                 else if (t->currentmaterialflags & MATERIALFLAG_REFRACTION)
1608                 {
1609                         mode = SHADERMODE_REFRACTION;
1610                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1611                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1612                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1613                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1614                 }
1615                 else
1616                 {
1617                         mode = SHADERMODE_GENERIC;
1618                         permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL;
1619                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1620                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1621                 }
1622                 if (vid.allowalphatocoverage)
1623                         GL_AlphaToCoverage(false);
1624         }
1625         else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
1626         {
1627                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1628                 {
1629                         switch(t->offsetmapping)
1630                         {
1631                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1632                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1633                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1634                         case OFFSETMAPPING_OFF: break;
1635                         }
1636                 }
1637                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1638                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1639                 // normalmap (deferred prepass), may use alpha test on diffuse
1640                 mode = SHADERMODE_DEFERREDGEOMETRY;
1641                 GL_BlendFunc(GL_ONE, GL_ZERO);
1642                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1643                 if (vid.allowalphatocoverage)
1644                         GL_AlphaToCoverage(false);
1645         }
1646         else if (rsurfacepass == RSURFPASS_RTLIGHT)
1647         {
1648                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1649                 {
1650                         switch(t->offsetmapping)
1651                         {
1652                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1653                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1654                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1655                         case OFFSETMAPPING_OFF: break;
1656                         }
1657                 }
1658                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1659                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1660                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1661                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1662                 // light source
1663                 mode = SHADERMODE_LIGHTSOURCE;
1664                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1665                         permutation |= SHADERPERMUTATION_CUBEFILTER;
1666                 if (VectorLength2(rtlightdiffuse) > 0)
1667                         permutation |= SHADERPERMUTATION_DIFFUSE;
1668                 if (VectorLength2(rtlightspecular) > 0)
1669                         permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1670                 if (r_refdef.fogenabled)
1671                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1672                 if (t->colormapping)
1673                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1674                 if (r_shadow_usingshadowmap2d)
1675                 {
1676                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1677                         if(r_shadow_shadowmapvsdct)
1678                                 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
1679
1680                         if (r_shadow_shadowmap2ddepthbuffer)
1681                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1682                 }
1683                 if (t->reflectmasktexture)
1684                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1685                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1686                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE);
1687                 if (vid.allowalphatocoverage)
1688                         GL_AlphaToCoverage(false);
1689         }
1690         else if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
1691         {
1692                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1693                 {
1694                         switch(t->offsetmapping)
1695                         {
1696                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1697                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1698                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1699                         case OFFSETMAPPING_OFF: break;
1700                         }
1701                 }
1702                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1703                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1704                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1705                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1706                 // directional model lighting
1707                 mode = SHADERMODE_LIGHTDIRECTION;
1708                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1709                         permutation |= SHADERPERMUTATION_GLOW;
1710                 if (VectorLength2(t->render_modellight_diffuse))
1711                         permutation |= SHADERPERMUTATION_DIFFUSE;
1712                 if (VectorLength2(t->render_modellight_specular) > 0)
1713                         permutation |= SHADERPERMUTATION_SPECULAR;
1714                 if (r_refdef.fogenabled)
1715                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1716                 if (t->colormapping)
1717                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1718                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1719                 {
1720                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1721                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1722
1723                         if (r_shadow_shadowmap2ddepthbuffer)
1724                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1725                 }
1726                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1727                         permutation |= SHADERPERMUTATION_REFLECTION;
1728                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1729                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1730                 if (t->reflectmasktexture)
1731                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1732                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1733                 {
1734                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1735                         if (r_shadow_bouncegrid_state.directional)
1736                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1737                 }
1738                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1739                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1740                 // when using alphatocoverage, we don't need alphakill
1741                 if (vid.allowalphatocoverage)
1742                 {
1743                         if (r_transparent_alphatocoverage.integer)
1744                         {
1745                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1746                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1747                         }
1748                         else
1749                                 GL_AlphaToCoverage(false);
1750                 }
1751         }
1752         else
1753         {
1754                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1755                 {
1756                         switch(t->offsetmapping)
1757                         {
1758                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1759                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1760                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1761                         case OFFSETMAPPING_OFF: break;
1762                         }
1763                 }
1764                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1765                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1766                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1767                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1768                 // lightmapped wall
1769                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1770                         permutation |= SHADERPERMUTATION_GLOW;
1771                 if (r_refdef.fogenabled)
1772                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1773                 if (t->colormapping)
1774                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1775                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1776                 {
1777                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1778                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1779
1780                         if (r_shadow_shadowmap2ddepthbuffer)
1781                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1782                 }
1783                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1784                         permutation |= SHADERPERMUTATION_REFLECTION;
1785                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1786                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1787                 if (t->reflectmasktexture)
1788                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1789                 if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
1790                 {
1791                         // deluxemapping (light direction texture)
1792                         if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace)
1793                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1794                         else
1795                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1796                         permutation |= SHADERPERMUTATION_DIFFUSE;
1797                         if (VectorLength2(t->render_lightmap_specular) > 0)
1798                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1799                 }
1800                 else if (r_glsl_deluxemapping.integer >= 2)
1801                 {
1802                         // fake deluxemapping (uniform light direction in tangentspace)
1803                         if (rsurface.uselightmaptexture)
1804                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP;
1805                         else
1806                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR;
1807                         permutation |= SHADERPERMUTATION_DIFFUSE;
1808                         if (VectorLength2(t->render_lightmap_specular) > 0)
1809                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1810                 }
1811                 else if (rsurface.uselightmaptexture)
1812                 {
1813                         // ordinary lightmapping (q1bsp, q3bsp)
1814                         mode = SHADERMODE_LIGHTMAP;
1815                 }
1816                 else
1817                 {
1818                         // ordinary vertex coloring (q3bsp)
1819                         mode = SHADERMODE_VERTEXCOLOR;
1820                 }
1821                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1822                 {
1823                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1824                         if (r_shadow_bouncegrid_state.directional)
1825                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1826                 }
1827                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1828                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1829                 // when using alphatocoverage, we don't need alphakill
1830                 if (vid.allowalphatocoverage)
1831                 {
1832                         if (r_transparent_alphatocoverage.integer)
1833                         {
1834                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1835                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1836                         }
1837                         else
1838                                 GL_AlphaToCoverage(false);
1839                 }
1840         }
1841         if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG))
1842                 permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE);
1843         if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1844                 permutation |= SHADERPERMUTATION_FOGALPHAHACK;
1845         switch(vid.renderpath)
1846         {
1847         case RENDERPATH_GL32:
1848         case RENDERPATH_GLES2:
1849                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | (rsurface.modellightmapcolor4f ? BATCHNEED_ARRAY_VERTEXCOLOR : 0) | BATCHNEED_ARRAY_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_ARRAY_LIGHTMAP : 0) | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
1850                 RSurf_UploadBuffersForBatch();
1851                 // this has to be after RSurf_PrepareVerticesForBatch
1852                 if (rsurface.batchskeletaltransform3x4buffer)
1853                         permutation |= SHADERPERMUTATION_SKELETAL;
1854                 R_SetupShader_SetPermutationGLSL(mode, permutation);
1855 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1856                 if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
1857 #endif
1858                 if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
1859                 if (mode == SHADERMODE_LIGHTSOURCE)
1860                 {
1861                         if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
1862                         if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1863                         if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1864                         if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
1865                         if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
1866                         if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
1867         
1868                         // additive passes are only darkened by fog, not tinted
1869                         if (r_glsl_permutation->loc_FogColor >= 0)
1870                                 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1871                         if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, t->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
1872                 }
1873                 else
1874                 {
1875                         if (mode == SHADERMODE_FLATCOLOR)
1876                         {
1877                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
1878                         }
1879                         else if (mode == SHADERMODE_LIGHTDIRECTION)
1880                         {
1881                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
1882                                 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_modellight_diffuse[0], t->render_modellight_diffuse[1], t->render_modellight_diffuse[2]);
1883                                 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_modellight_specular[0], t->render_modellight_specular[1], t->render_modellight_specular[2]);
1884                                 if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, t->render_rtlight_diffuse[0], t->render_rtlight_diffuse[1], t->render_rtlight_diffuse[2]);
1885                                 if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, t->render_rtlight_specular[0], t->render_rtlight_specular[1], t->render_rtlight_specular[2]);
1886                                 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1887                                 if (r_glsl_permutation->loc_LightDir >= 0) qglUniform3f(r_glsl_permutation->loc_LightDir, t->render_modellight_lightdir[0], t->render_modellight_lightdir[1], t->render_modellight_lightdir[2]);
1888                         }
1889                         else
1890                         {
1891                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_lightmap_ambient[0], t->render_lightmap_ambient[1], t->render_lightmap_ambient[2]);
1892                                 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_lightmap_diffuse[0], t->render_lightmap_diffuse[1], t->render_lightmap_diffuse[2]);
1893                                 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_lightmap_specular[0], t->render_lightmap_specular[1], t->render_lightmap_specular[2]);
1894                                 if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, t->render_rtlight_diffuse[0], t->render_rtlight_diffuse[1], t->render_rtlight_diffuse[2]);
1895                                 if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, t->render_rtlight_specular[0], t->render_rtlight_specular[1], t->render_rtlight_specular[2]);
1896                         }
1897                         // additive passes are only darkened by fog, not tinted
1898                         if (r_glsl_permutation->loc_FogColor >= 0)
1899                         {
1900                                 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
1901                                         qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1902                                 else
1903                                         qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1904                         }
1905                         if (r_glsl_permutation->loc_DistortScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_DistortScaleRefractReflect, r_water_refractdistort.value * t->refractfactor, r_water_refractdistort.value * t->refractfactor, r_water_reflectdistort.value * t->reflectfactor, r_water_reflectdistort.value * t->reflectfactor);
1906                         if (r_glsl_permutation->loc_ScreenScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenScaleRefractReflect, r_fb.water.screenscale[0], r_fb.water.screenscale[1], r_fb.water.screenscale[0], r_fb.water.screenscale[1]);
1907                         if (r_glsl_permutation->loc_ScreenCenterRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenCenterRefractReflect, r_fb.water.screencenter[0], r_fb.water.screencenter[1], r_fb.water.screencenter[0], r_fb.water.screencenter[1]);
1908                         if (r_glsl_permutation->loc_RefractColor >= 0) qglUniform4f(r_glsl_permutation->loc_RefractColor, t->refractcolor4f[0], t->refractcolor4f[1], t->refractcolor4f[2], t->refractcolor4f[3] * t->currentalpha);
1909                         if (r_glsl_permutation->loc_ReflectColor >= 0) qglUniform4f(r_glsl_permutation->loc_ReflectColor, t->reflectcolor4f[0], t->reflectcolor4f[1], t->reflectcolor4f[2], t->reflectcolor4f[3] * t->currentalpha);
1910                         if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, t->reflectmax - t->reflectmin);
1911                         if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, t->reflectmin);
1912                         if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, t->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
1913                         if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
1914                 }
1915                 if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
1916                 if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
1917                 if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
1918                 if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
1919                 {
1920                         if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_modelshadowmap_texturescale[0], r_shadow_modelshadowmap_texturescale[1], r_shadow_modelshadowmap_texturescale[2], r_shadow_modelshadowmap_texturescale[3]);
1921                         if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_modelshadowmap_parameters[0], r_shadow_modelshadowmap_parameters[1], r_shadow_modelshadowmap_parameters[2], r_shadow_modelshadowmap_parameters[3]);
1922                 }
1923                 else
1924                 {
1925                         if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
1926                         if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
1927                 }
1928
1929                 if (r_glsl_permutation->loc_Color_Glow >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Glow, t->render_glowmod[0], t->render_glowmod[1], t->render_glowmod[2]);
1930                 if (r_glsl_permutation->loc_Alpha >= 0) qglUniform1f(r_glsl_permutation->loc_Alpha, t->currentalpha * ((t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? t->r_water_wateralpha : 1));
1931                 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
1932                 if (r_glsl_permutation->loc_Color_Pants >= 0)
1933                 {
1934                         if (t->pantstexture)
1935                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
1936                         else
1937                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
1938                 }
1939                 if (r_glsl_permutation->loc_Color_Shirt >= 0)
1940                 {
1941                         if (t->shirttexture)
1942                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
1943                         else
1944                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
1945                 }
1946                 if (r_glsl_permutation->loc_FogPlane >= 0) qglUniform4f(r_glsl_permutation->loc_FogPlane, rsurface.fogplane[0], rsurface.fogplane[1], rsurface.fogplane[2], rsurface.fogplane[3]);
1947                 if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
1948                 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
1949                 if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
1950                 if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps,
1951                                 r_glsl_offsetmapping_scale.value*t->offsetscale,
1952                                 max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
1953                                 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
1954                                 max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
1955                         );
1956                 if (r_glsl_permutation->loc_OffsetMapping_LodDistance >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer * r_refdef.view.quality);
1957                 if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, t->offsetbias);
1958                 if (r_glsl_permutation->loc_ScreenToDepth >= 0) qglUniform2f(r_glsl_permutation->loc_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
1959                 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
1960                 if (r_glsl_permutation->loc_BounceGridMatrix >= 0) {Matrix4x4_Concat(&tempmatrix, &r_shadow_bouncegrid_state.matrix, &rsurface.matrix);Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BounceGridMatrix, 1, false, m16f);}
1961                 if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
1962
1963                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First            , r_texture_white                                     );
1964                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second           , r_texture_white                                     );
1965                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps       , r_texture_gammaramps                                );
1966                 if (r_glsl_permutation->tex_Texture_Normal          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal           , t->nmaptexture                       );
1967                 if (r_glsl_permutation->tex_Texture_Color           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color            , t->basetexture                       );
1968                 if (r_glsl_permutation->tex_Texture_Gloss           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss            , t->glosstexture                      );
1969                 if (r_glsl_permutation->tex_Texture_Glow            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow             , t->glowtexture                       );
1970                 if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal  , t->backgroundnmaptexture             );
1971                 if (r_glsl_permutation->tex_Texture_SecondaryColor  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor   , t->backgroundbasetexture             );
1972                 if (r_glsl_permutation->tex_Texture_SecondaryGloss  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss   , t->backgroundglosstexture            );
1973                 if (r_glsl_permutation->tex_Texture_SecondaryGlow   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow    , t->backgroundglowtexture             );
1974                 if (r_glsl_permutation->tex_Texture_Pants           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants            , t->pantstexture                      );
1975                 if (r_glsl_permutation->tex_Texture_Shirt           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt            , t->shirttexture                      );
1976                 if (r_glsl_permutation->tex_Texture_ReflectMask     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask      , t->reflectmasktexture                );
1977                 if (r_glsl_permutation->tex_Texture_ReflectCube     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube      , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
1978                 if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture                          );
1979                 if (r_glsl_permutation->tex_Texture_FogMask         >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask          , r_texture_fogattenuation                            );
1980                 if (r_glsl_permutation->tex_Texture_Lightmap        >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap         , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
1981                 if (r_glsl_permutation->tex_Texture_Deluxemap       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Deluxemap        , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap);
1982                 if (r_glsl_permutation->tex_Texture_Attenuation     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation      , r_shadow_attenuationgradienttexture                 );
1983                 if (rsurfacepass == RSURFPASS_BACKGROUND)
1984                 {
1985                         if (r_glsl_permutation->tex_Texture_Refraction  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Refraction        , waterplane->rt_refraction ? waterplane->rt_refraction->colortexture[0] : r_texture_black);
1986                         if (r_glsl_permutation->tex_Texture_First       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First             , waterplane->rt_camera ? waterplane->rt_camera->colortexture[0] : r_texture_black);
1987                         if (r_glsl_permutation->tex_Texture_Reflection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection        , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
1988                 }
1989                 else
1990                 {
1991                         if (r_glsl_permutation->tex_Texture_Reflection >= 0 && waterplane) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection        , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
1992                 }
1993                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap   , r_shadow_prepassgeometrynormalmaptexture            );
1994                 if (r_glsl_permutation->tex_Texture_ScreenDiffuse   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse     , r_shadow_prepasslightingdiffusetexture              );
1995                 if (r_glsl_permutation->tex_Texture_ScreenSpecular  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular    , r_shadow_prepasslightingspeculartexture             );
1996                 if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
1997                 {
1998                         if (r_glsl_permutation->tex_Texture_ShadowMap2D     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture                           );
1999                         if (rsurface.rtlight)
2000                         {
2001                                 if (r_glsl_permutation->tex_Texture_Cube            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube              , rsurface.rtlight->currentcubemap                    );
2002                                 if (r_glsl_permutation->tex_Texture_CubeProjection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection    , r_shadow_shadowmapvsdcttexture                      );
2003                         }
2004                 }
2005                 if (r_glsl_permutation->tex_Texture_BounceGrid  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
2006                 CHECKGLERROR
2007                 break;
2008         }
2009 }
2010
2011 void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
2012 {
2013         // select a permutation of the lighting shader appropriate to this
2014         // combination of texture, entity, light source, and fogging, only use the
2015         // minimum features necessary to avoid wasting rendering time in the
2016         // fragment shader on features that are not being used
2017         dpuint64 permutation = 0;
2018         unsigned int mode = 0;
2019         const float *lightcolorbase = rtlight->currentcolor;
2020         float ambientscale = rtlight->ambientscale;
2021         float diffusescale = rtlight->diffusescale;
2022         float specularscale = rtlight->specularscale;
2023         // this is the location of the light in view space
2024         vec3_t viewlightorigin;
2025         // this transforms from view space (camera) to light space (cubemap)
2026         matrix4x4_t viewtolight;
2027         matrix4x4_t lighttoview;
2028         float viewtolight16f[16];
2029         // light source
2030         mode = SHADERMODE_DEFERREDLIGHTSOURCE;
2031         if (rtlight->currentcubemap != r_texture_whitecube)
2032                 permutation |= SHADERPERMUTATION_CUBEFILTER;
2033         if (diffusescale > 0)
2034                 permutation |= SHADERPERMUTATION_DIFFUSE;
2035         if (specularscale > 0 && r_shadow_gloss.integer > 0)
2036                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2037         if (r_shadow_usingshadowmap2d)
2038         {
2039                 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
2040                 if (r_shadow_shadowmapvsdct)
2041                         permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
2042
2043                 if (r_shadow_shadowmap2ddepthbuffer)
2044                         permutation |= SHADERPERMUTATION_DEPTHRGB;
2045         }
2046         if (vid.allowalphatocoverage)
2047                 GL_AlphaToCoverage(false);
2048         Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
2049         Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
2050         Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
2051         Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
2052         switch(vid.renderpath)
2053         {
2054         case RENDERPATH_GL32:
2055         case RENDERPATH_GLES2:
2056                 R_SetupShader_SetPermutationGLSL(mode, permutation);
2057                 if (r_glsl_permutation->loc_LightPosition             >= 0) qglUniform3f(       r_glsl_permutation->loc_LightPosition            , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
2058                 if (r_glsl_permutation->loc_ViewToLight               >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight              , 1, false, viewtolight16f);
2059                 if (r_glsl_permutation->loc_DeferredColor_Ambient     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Ambient    , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
2060                 if (r_glsl_permutation->loc_DeferredColor_Diffuse     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
2061                 if (r_glsl_permutation->loc_DeferredColor_Specular    >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Specular   , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
2062                 if (r_glsl_permutation->loc_ShadowMap_TextureScale    >= 0) qglUniform4f(       r_glsl_permutation->loc_ShadowMap_TextureScale   , r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
2063                 if (r_glsl_permutation->loc_ShadowMap_Parameters      >= 0) qglUniform4f(       r_glsl_permutation->loc_ShadowMap_Parameters     , r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
2064                 if (r_glsl_permutation->loc_SpecularPower             >= 0) qglUniform1f(       r_glsl_permutation->loc_SpecularPower            , (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
2065                 if (r_glsl_permutation->loc_ScreenToDepth             >= 0) qglUniform2f(       r_glsl_permutation->loc_ScreenToDepth            , r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
2066                 if (r_glsl_permutation->loc_PixelToScreenTexCoord     >= 0) qglUniform2f(       r_glsl_permutation->loc_PixelToScreenTexCoord    , 1.0f/vid.width, 1.0f/vid.height);
2067
2068                 if (r_glsl_permutation->tex_Texture_Attenuation       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation        , r_shadow_attenuationgradienttexture                 );
2069                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap    , r_shadow_prepassgeometrynormalmaptexture            );
2070                 if (r_glsl_permutation->tex_Texture_Cube              >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube               , rsurface.rtlight->currentcubemap                    );
2071                 if (r_glsl_permutation->tex_Texture_ShadowMap2D       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D        , r_shadow_shadowmap2ddepthtexture                    );
2072                 if (r_glsl_permutation->tex_Texture_CubeProjection    >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection     , r_shadow_shadowmapvsdcttexture                      );
2073                 break;
2074         }
2075 }
2076
2077 #define SKINFRAME_HASH 1024
2078
2079 typedef struct
2080 {
2081         unsigned int loadsequence; // incremented each level change
2082         memexpandablearray_t array;
2083         skinframe_t *hash[SKINFRAME_HASH];
2084 }
2085 r_skinframe_t;
2086 r_skinframe_t r_skinframe;
2087
2088 void R_SkinFrame_PrepareForPurge(void)
2089 {
2090         r_skinframe.loadsequence++;
2091         // wrap it without hitting zero
2092         if (r_skinframe.loadsequence >= 200)
2093                 r_skinframe.loadsequence = 1;
2094 }
2095
2096 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
2097 {
2098         if (!skinframe)
2099                 return;
2100         // mark the skinframe as used for the purging code
2101         skinframe->loadsequence = r_skinframe.loadsequence;
2102 }
2103
2104 void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
2105 {
2106         if (s == NULL)
2107                 return;
2108         if (s->merged == s->base)
2109                 s->merged = NULL;
2110         R_PurgeTexture(s->stain); s->stain = NULL;
2111         R_PurgeTexture(s->merged); s->merged = NULL;
2112         R_PurgeTexture(s->base); s->base = NULL;
2113         R_PurgeTexture(s->pants); s->pants = NULL;
2114         R_PurgeTexture(s->shirt); s->shirt = NULL;
2115         R_PurgeTexture(s->nmap); s->nmap = NULL;
2116         R_PurgeTexture(s->gloss); s->gloss = NULL;
2117         R_PurgeTexture(s->glow); s->glow = NULL;
2118         R_PurgeTexture(s->fog); s->fog = NULL;
2119         R_PurgeTexture(s->reflect); s->reflect = NULL;
2120         s->loadsequence = 0;
2121 }
2122
2123 void R_SkinFrame_Purge(void)
2124 {
2125         int i;
2126         skinframe_t *s;
2127         for (i = 0;i < SKINFRAME_HASH;i++)
2128         {
2129                 for (s = r_skinframe.hash[i];s;s = s->next)
2130                 {
2131                         if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
2132                                 R_SkinFrame_PurgeSkinFrame(s);
2133                 }
2134         }
2135 }
2136
2137 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
2138         skinframe_t *item;
2139         char basename[MAX_QPATH];
2140
2141         Image_StripImageExtension(name, basename, sizeof(basename));
2142
2143         if( last == NULL ) {
2144                 int hashindex;
2145                 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2146                 item = r_skinframe.hash[hashindex];
2147         } else {
2148                 item = last->next;
2149         }
2150
2151         // linearly search through the hash bucket
2152         for( ; item ; item = item->next ) {
2153                 if( !strcmp( item->basename, basename ) ) {
2154                         return item;
2155                 }
2156         }
2157         return NULL;
2158 }
2159
2160 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add)
2161 {
2162         skinframe_t *item;
2163         int compareflags = textureflags & TEXF_IMPORTANTBITS;
2164         int hashindex;
2165         char basename[MAX_QPATH];
2166
2167         Image_StripImageExtension(name, basename, sizeof(basename));
2168
2169         hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2170         for (item = r_skinframe.hash[hashindex];item;item = item->next)
2171                 if (!strcmp(item->basename, basename) &&
2172                         item->textureflags == compareflags &&
2173                         item->comparewidth == comparewidth &&
2174                         item->compareheight == compareheight &&
2175                         item->comparecrc == comparecrc)
2176                         break;
2177
2178         if (!item)
2179         {
2180                 if (!add)
2181                         return NULL;
2182                 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
2183                 memset(item, 0, sizeof(*item));
2184                 strlcpy(item->basename, basename, sizeof(item->basename));
2185                 item->textureflags = compareflags;
2186                 item->comparewidth = comparewidth;
2187                 item->compareheight = compareheight;
2188                 item->comparecrc = comparecrc;
2189                 item->next = r_skinframe.hash[hashindex];
2190                 r_skinframe.hash[hashindex] = item;
2191         }
2192         else if (textureflags & TEXF_FORCE_RELOAD)
2193                 R_SkinFrame_PurgeSkinFrame(item);
2194
2195         R_SkinFrame_MarkUsed(item);
2196         return item;
2197 }
2198
2199 #define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
2200         { \
2201                 unsigned long long avgcolor[5], wsum; \
2202                 int pix, comp, w; \
2203                 avgcolor[0] = 0; \
2204                 avgcolor[1] = 0; \
2205                 avgcolor[2] = 0; \
2206                 avgcolor[3] = 0; \
2207                 avgcolor[4] = 0; \
2208                 wsum = 0; \
2209                 for(pix = 0; pix < cnt; ++pix) \
2210                 { \
2211                         w = 0; \
2212                         for(comp = 0; comp < 3; ++comp) \
2213                                 w += getpixel; \
2214                         if(w) /* ignore perfectly black pixels because that is better for model skins */ \
2215                         { \
2216                                 ++wsum; \
2217                                 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2218                                 w = getpixel; \
2219                                 for(comp = 0; comp < 3; ++comp) \
2220                                         avgcolor[comp] += getpixel * w; \
2221                                 avgcolor[3] += w; \
2222                         } \
2223                         /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2224                         avgcolor[4] += getpixel; \
2225                 } \
2226                 if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
2227                         avgcolor[3] = 1; \
2228                 skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
2229                 skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
2230                 skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
2231                 skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
2232         }
2233
2234 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2235 {
2236         skinframe_t *skinframe;
2237
2238         if (cls.state == ca_dedicated)
2239                 return NULL;
2240
2241         // return an existing skinframe if already loaded
2242         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
2243         if (skinframe && skinframe->base)
2244                 return skinframe;
2245
2246         // if the skinframe doesn't exist this will create it
2247         return R_SkinFrame_LoadExternal_SkinFrame(skinframe, name, textureflags, complain, fallbacknotexture);
2248 }
2249
2250 extern cvar_t gl_picmip;
2251 skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2252 {
2253         int j;
2254         unsigned char *pixels;
2255         unsigned char *bumppixels;
2256         unsigned char *basepixels = NULL;
2257         int basepixels_width = 0;
2258         int basepixels_height = 0;
2259         rtexture_t *ddsbase = NULL;
2260         qboolean ddshasalpha = false;
2261         float ddsavgcolor[4];
2262         char basename[MAX_QPATH];
2263         int miplevel = R_PicmipForFlags(textureflags);
2264         int savemiplevel = miplevel;
2265         int mymiplevel;
2266         char vabuf[1024];
2267
2268         if (cls.state == ca_dedicated)
2269                 return NULL;
2270
2271         Image_StripImageExtension(name, basename, sizeof(basename));
2272
2273         // check for DDS texture file first
2274         if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2275         {
2276                 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2277                 if (basepixels == NULL && fallbacknotexture)
2278                         basepixels = Image_GenerateNoTexture();
2279                 if (basepixels == NULL)
2280                         return NULL;
2281         }
2282
2283         // FIXME handle miplevel
2284
2285         if (developer_loading.integer)
2286                 Con_Printf("loading skin \"%s\"\n", name);
2287
2288         // we've got some pixels to store, so really allocate this new texture now
2289         if (!skinframe)
2290                 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2291         textureflags &= ~TEXF_FORCE_RELOAD;
2292         skinframe->stain = NULL;
2293         skinframe->merged = NULL;
2294         skinframe->base = NULL;
2295         skinframe->pants = NULL;
2296         skinframe->shirt = NULL;
2297         skinframe->nmap = NULL;
2298         skinframe->gloss = NULL;
2299         skinframe->glow = NULL;
2300         skinframe->fog = NULL;
2301         skinframe->reflect = NULL;
2302         skinframe->hasalpha = false;
2303         // we could store the q2animname here too
2304
2305         if (ddsbase)
2306         {
2307                 skinframe->base = ddsbase;
2308                 skinframe->hasalpha = ddshasalpha;
2309                 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2310                 if (r_loadfog && skinframe->hasalpha)
2311                         skinframe->fog = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), false, textureflags | TEXF_ALPHA, NULL, NULL, miplevel, true);
2312                 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2313         }
2314         else
2315         {
2316                 basepixels_width = image_width;
2317                 basepixels_height = image_height;
2318                 skinframe->base = R_LoadTexture2D (r_main_texturepool, skinframe->basename, basepixels_width, basepixels_height, basepixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL);
2319                 if (textureflags & TEXF_ALPHA)
2320                 {
2321                         for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2322                         {
2323                                 if (basepixels[j] < 255)
2324                                 {
2325                                         skinframe->hasalpha = true;
2326                                         break;
2327                                 }
2328                         }
2329                         if (r_loadfog && skinframe->hasalpha)
2330                         {
2331                                 // has transparent pixels
2332                                 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2333                                 for (j = 0;j < image_width * image_height * 4;j += 4)
2334                                 {
2335                                         pixels[j+0] = 255;
2336                                         pixels[j+1] = 255;
2337                                         pixels[j+2] = 255;
2338                                         pixels[j+3] = basepixels[j+3];
2339                                 }
2340                                 skinframe->fog = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_mask", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL);
2341                                 Mem_Free(pixels);
2342                         }
2343                 }
2344                 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2345 #ifndef USE_GLES2
2346                 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2347                 if (r_savedds && skinframe->base)
2348                         R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2349                 if (r_savedds && skinframe->fog)
2350                         R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2351 #endif
2352         }
2353
2354         if (r_loaddds)
2355         {
2356                 mymiplevel = savemiplevel;
2357                 if (r_loadnormalmap)
2358                         skinframe->nmap = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), false, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), NULL, NULL, mymiplevel, true);
2359                 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2360                 if (r_loadgloss)
2361                         skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2362                 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2363                 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2364                 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2365         }
2366
2367         // _norm is the name used by tenebrae and has been adopted as standard
2368         if (r_loadnormalmap && skinframe->nmap == NULL)
2369         {
2370                 mymiplevel = savemiplevel;
2371                 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2372                 {
2373                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2374                         Mem_Free(pixels);
2375                         pixels = NULL;
2376                 }
2377                 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2378                 {
2379                         pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2380                         Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2381                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2382                         Mem_Free(pixels);
2383                         Mem_Free(bumppixels);
2384                 }
2385                 else if (r_shadow_bumpscale_basetexture.value > 0)
2386                 {
2387                         pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2388                         Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2389                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), basepixels_width, basepixels_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2390                         Mem_Free(pixels);
2391                 }
2392 #ifndef USE_GLES2
2393                 if (r_savedds && skinframe->nmap)
2394                         R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2395 #endif
2396         }
2397
2398         // _luma is supported only for tenebrae compatibility
2399         // _glow is the preferred name
2400         mymiplevel = savemiplevel;
2401         if (skinframe->glow == NULL && ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_glow",  skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_luma", skinframe->basename), false, false, false, &mymiplevel))))
2402         {
2403                 skinframe->glow = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_glow.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2404 #ifndef USE_GLES2
2405                 if (r_savedds && skinframe->glow)
2406                         R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2407 #endif
2408                 Mem_Free(pixels);pixels = NULL;
2409         }
2410
2411         mymiplevel = savemiplevel;
2412         if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2413         {
2414                 skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (gl_texturecompression_gloss.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2415 #ifndef USE_GLES2
2416                 if (r_savedds && skinframe->gloss)
2417                         R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2418 #endif
2419                 Mem_Free(pixels);
2420                 pixels = NULL;
2421         }
2422
2423         mymiplevel = savemiplevel;
2424         if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2425         {
2426                 skinframe->pants = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2427 #ifndef USE_GLES2
2428                 if (r_savedds && skinframe->pants)
2429                         R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2430 #endif
2431                 Mem_Free(pixels);
2432                 pixels = NULL;
2433         }
2434
2435         mymiplevel = savemiplevel;
2436         if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2437         {
2438                 skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2439 #ifndef USE_GLES2
2440                 if (r_savedds && skinframe->shirt)
2441                         R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2442 #endif
2443                 Mem_Free(pixels);
2444                 pixels = NULL;
2445         }
2446
2447         mymiplevel = savemiplevel;
2448         if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2449         {
2450                 skinframe->reflect = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_reflectmask.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2451 #ifndef USE_GLES2
2452                 if (r_savedds && skinframe->reflect)
2453                         R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2454 #endif
2455                 Mem_Free(pixels);
2456                 pixels = NULL;
2457         }
2458
2459         if (basepixels)
2460                 Mem_Free(basepixels);
2461
2462         return skinframe;
2463 }
2464
2465 skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, int comparewidth, int compareheight, int comparecrc, qboolean sRGB)
2466 {
2467         int i;
2468         skinframe_t *skinframe;
2469         char vabuf[1024];
2470
2471         if (cls.state == ca_dedicated)
2472                 return NULL;
2473
2474         // if already loaded just return it, otherwise make a new skinframe
2475         skinframe = R_SkinFrame_Find(name, textureflags, comparewidth, compareheight, comparecrc, true);
2476         if (skinframe->base)
2477                 return skinframe;
2478         textureflags &= ~TEXF_FORCE_RELOAD;
2479
2480         skinframe->stain = NULL;
2481         skinframe->merged = NULL;
2482         skinframe->base = NULL;
2483         skinframe->pants = NULL;
2484         skinframe->shirt = NULL;
2485         skinframe->nmap = NULL;
2486         skinframe->gloss = NULL;
2487         skinframe->glow = NULL;
2488         skinframe->fog = NULL;
2489         skinframe->reflect = NULL;
2490         skinframe->hasalpha = false;
2491
2492         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2493         if (!skindata)
2494                 return NULL;
2495
2496         if (developer_loading.integer)
2497                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2498
2499         if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2500         {
2501                 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2502                 unsigned char *b = a + width * height * 4;
2503                 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2504                 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, b, TEXTYPE_BGRA, (textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
2505                 Mem_Free(a);
2506         }
2507         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2508         if (textureflags & TEXF_ALPHA)
2509         {
2510                 for (i = 3;i < width * height * 4;i += 4)
2511                 {
2512                         if (skindata[i] < 255)
2513                         {
2514                                 skinframe->hasalpha = true;
2515                                 break;
2516                         }
2517                 }
2518                 if (r_loadfog && skinframe->hasalpha)
2519                 {
2520                         unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2521                         memcpy(fogpixels, skindata, width * height * 4);
2522                         for (i = 0;i < width * height * 4;i += 4)
2523                                 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2524                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2525                         Mem_Free(fogpixels);
2526                 }
2527         }
2528
2529         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2530         //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2531
2532         return skinframe;
2533 }
2534
2535 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2536 {
2537         int i;
2538         int featuresmask;
2539         skinframe_t *skinframe;
2540
2541         if (cls.state == ca_dedicated)
2542                 return NULL;
2543
2544         // if already loaded just return it, otherwise make a new skinframe
2545         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2546         if (skinframe->base)
2547                 return skinframe;
2548         //textureflags &= ~TEXF_FORCE_RELOAD;
2549
2550         skinframe->stain = NULL;
2551         skinframe->merged = NULL;
2552         skinframe->base = NULL;
2553         skinframe->pants = NULL;
2554         skinframe->shirt = NULL;
2555         skinframe->nmap = NULL;
2556         skinframe->gloss = NULL;
2557         skinframe->glow = NULL;
2558         skinframe->fog = NULL;
2559         skinframe->reflect = NULL;
2560         skinframe->hasalpha = false;
2561
2562         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2563         if (!skindata)
2564                 return NULL;
2565
2566         if (developer_loading.integer)
2567                 Con_Printf("loading quake skin \"%s\"\n", name);
2568
2569         // we actually don't upload anything until the first use, because mdl skins frequently go unused, and are almost never used in both modes (colormapped and non-colormapped)
2570         skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2571         memcpy(skinframe->qpixels, skindata, width*height);
2572         skinframe->qwidth = width;
2573         skinframe->qheight = height;
2574
2575         featuresmask = 0;
2576         for (i = 0;i < width * height;i++)
2577                 featuresmask |= palette_featureflags[skindata[i]];
2578
2579         skinframe->hasalpha = false;
2580         // fence textures
2581         if (name[0] == '{')
2582                 skinframe->hasalpha = true;
2583         skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2584         skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2585         skinframe->qgeneratemerged = true;
2586         skinframe->qgeneratebase = skinframe->qhascolormapping;
2587         skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2588
2589         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2590         //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2591
2592         return skinframe;
2593 }
2594
2595 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboolean colormapped)
2596 {
2597         int width;
2598         int height;
2599         unsigned char *skindata;
2600         char vabuf[1024];
2601
2602         if (!skinframe->qpixels)
2603                 return;
2604
2605         if (!skinframe->qhascolormapping)
2606                 colormapped = false;
2607
2608         if (colormapped)
2609         {
2610                 if (!skinframe->qgeneratebase)
2611                         return;
2612         }
2613         else
2614         {
2615                 if (!skinframe->qgeneratemerged)
2616                         return;
2617         }
2618
2619         width = skinframe->qwidth;
2620         height = skinframe->qheight;
2621         skindata = skinframe->qpixels;
2622
2623         if (skinframe->qgeneratenmap)
2624         {
2625                 unsigned char *a, *b;
2626                 skinframe->qgeneratenmap = false;
2627                 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2628                 b = a + width * height * 4;
2629                 // use either a custom palette or the quake palette
2630                 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2631                 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2632                 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, b, TEXTYPE_BGRA, (skinframe->textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
2633                 Mem_Free(a);
2634         }
2635
2636         if (skinframe->qgenerateglow)
2637         {
2638                 skinframe->qgenerateglow = false;
2639                 if (skinframe->hasalpha) // fence textures
2640                         skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags | TEXF_ALPHA, -1, palette_bgra_onlyfullbrights_transparent); // glow
2641                 else
2642                         skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_onlyfullbrights); // glow
2643         }
2644
2645         if (colormapped)
2646         {
2647                 skinframe->qgeneratebase = false;
2648                 skinframe->base  = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nospecial", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nocolormapnofullbrights : palette_bgra_nocolormap);
2649                 skinframe->pants = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_pantsaswhite);
2650                 skinframe->shirt = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_shirtaswhite);
2651         }
2652         else
2653         {
2654                 skinframe->qgeneratemerged = false;
2655                 if (skinframe->hasalpha) // fence textures
2656                         skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags | TEXF_ALPHA, -1, skinframe->glow ? palette_bgra_nofullbrights_transparent : palette_bgra_transparent);
2657                 else
2658                         skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nofullbrights : palette_bgra_complete);
2659         }
2660
2661         if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2662         {
2663                 Mem_Free(skinframe->qpixels);
2664                 skinframe->qpixels = NULL;
2665         }
2666 }
2667
2668 skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, const unsigned char *skindata, int width, int height, const unsigned int *palette, const unsigned int *alphapalette)
2669 {
2670         int i;
2671         skinframe_t *skinframe;
2672         char vabuf[1024];
2673
2674         if (cls.state == ca_dedicated)
2675                 return NULL;
2676
2677         // if already loaded just return it, otherwise make a new skinframe
2678         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2679         if (skinframe->base)
2680                 return skinframe;
2681         textureflags &= ~TEXF_FORCE_RELOAD;
2682
2683         skinframe->stain = NULL;
2684         skinframe->merged = NULL;
2685         skinframe->base = NULL;
2686         skinframe->pants = NULL;
2687         skinframe->shirt = NULL;
2688         skinframe->nmap = NULL;
2689         skinframe->gloss = NULL;
2690         skinframe->glow = NULL;
2691         skinframe->fog = NULL;
2692         skinframe->reflect = NULL;
2693         skinframe->hasalpha = false;
2694
2695         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2696         if (!skindata)
2697                 return NULL;
2698
2699         if (developer_loading.integer)
2700                 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2701
2702         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2703         if ((textureflags & TEXF_ALPHA) && alphapalette)
2704         {
2705                 for (i = 0;i < width * height;i++)
2706                 {
2707                         if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2708                         {
2709                                 skinframe->hasalpha = true;
2710                                 break;
2711                         }
2712                 }
2713                 if (r_loadfog && skinframe->hasalpha)
2714                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2715         }
2716
2717         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2718         //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2719
2720         return skinframe;
2721 }
2722
2723 skinframe_t *R_SkinFrame_LoadMissing(void)
2724 {
2725         skinframe_t *skinframe;
2726
2727         if (cls.state == ca_dedicated)
2728                 return NULL;
2729
2730         skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2731         skinframe->stain = NULL;
2732         skinframe->merged = NULL;
2733         skinframe->base = NULL;
2734         skinframe->pants = NULL;
2735         skinframe->shirt = NULL;
2736         skinframe->nmap = NULL;
2737         skinframe->gloss = NULL;
2738         skinframe->glow = NULL;
2739         skinframe->fog = NULL;
2740         skinframe->reflect = NULL;
2741         skinframe->hasalpha = false;
2742
2743         skinframe->avgcolor[0] = rand() / RAND_MAX;
2744         skinframe->avgcolor[1] = rand() / RAND_MAX;
2745         skinframe->avgcolor[2] = rand() / RAND_MAX;
2746         skinframe->avgcolor[3] = 1;
2747
2748         return skinframe;
2749 }
2750
2751 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2752 {
2753         int x, y;
2754         static unsigned char pix[16][16][4];
2755
2756         if (cls.state == ca_dedicated)
2757                 return NULL;
2758
2759         // this makes a light grey/dark grey checkerboard texture
2760         if (!pix[0][0][3])
2761         {
2762                 for (y = 0; y < 16; y++)
2763                 {
2764                         for (x = 0; x < 16; x++)
2765                         {
2766                                 if ((y < 8) ^ (x < 8))
2767                                 {
2768                                         pix[y][x][0] = 128;
2769                                         pix[y][x][1] = 128;
2770                                         pix[y][x][2] = 128;
2771                                         pix[y][x][3] = 255;
2772                                 }
2773                                 else
2774                                 {
2775                                         pix[y][x][0] = 64;
2776                                         pix[y][x][1] = 64;
2777                                         pix[y][x][2] = 64;
2778                                         pix[y][x][3] = 255;
2779                                 }
2780                         }
2781                 }
2782         }
2783
2784         return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, pix[0][0], 16, 16, 0, 0, 0, false);
2785 }
2786
2787 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qboolean sRGB)
2788 {
2789         skinframe_t *skinframe;
2790         if (cls.state == ca_dedicated)
2791                 return NULL;
2792         // if already loaded just return it, otherwise make a new skinframe
2793         skinframe = R_SkinFrame_Find(name, textureflags, width, height, 0, true);
2794         if (skinframe->base)
2795                 return skinframe;
2796         textureflags &= ~TEXF_FORCE_RELOAD;
2797         skinframe->stain = NULL;
2798         skinframe->merged = NULL;
2799         skinframe->base = NULL;
2800         skinframe->pants = NULL;
2801         skinframe->shirt = NULL;
2802         skinframe->nmap = NULL;
2803         skinframe->gloss = NULL;
2804         skinframe->glow = NULL;
2805         skinframe->fog = NULL;
2806         skinframe->reflect = NULL;
2807         skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2808         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2809         if (!tex)
2810                 return NULL;
2811         if (developer_loading.integer)
2812                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2813         skinframe->base = skinframe->merged = tex;
2814         Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2815         return skinframe;
2816 }
2817
2818 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2819 typedef struct suffixinfo_s
2820 {
2821         const char *suffix;
2822         qboolean flipx, flipy, flipdiagonal;
2823 }
2824 suffixinfo_t;
2825 static suffixinfo_t suffix[3][6] =
2826 {
2827         {
2828                 {"px",   false, false, false},
2829                 {"nx",   false, false, false},
2830                 {"py",   false, false, false},
2831                 {"ny",   false, false, false},
2832                 {"pz",   false, false, false},
2833                 {"nz",   false, false, false}
2834         },
2835         {
2836                 {"posx", false, false, false},
2837                 {"negx", false, false, false},
2838                 {"posy", false, false, false},
2839                 {"negy", false, false, false},
2840                 {"posz", false, false, false},
2841                 {"negz", false, false, false}
2842         },
2843         {
2844                 {"rt",    true, false,  true},
2845                 {"lf",   false,  true,  true},
2846                 {"ft",    true,  true, false},
2847                 {"bk",   false, false, false},
2848                 {"up",    true, false,  true},
2849                 {"dn",    true, false,  true}
2850         }
2851 };
2852
2853 static int componentorder[4] = {0, 1, 2, 3};
2854
2855 static rtexture_t *R_LoadCubemap(const char *basename)
2856 {
2857         int i, j, cubemapsize;
2858         unsigned char *cubemappixels, *image_buffer;
2859         rtexture_t *cubemaptexture;
2860         char name[256];
2861         // must start 0 so the first loadimagepixels has no requested width/height
2862         cubemapsize = 0;
2863         cubemappixels = NULL;
2864         cubemaptexture = NULL;
2865         // keep trying different suffix groups (posx, px, rt) until one loads
2866         for (j = 0;j < 3 && !cubemappixels;j++)
2867         {
2868                 // load the 6 images in the suffix group
2869                 for (i = 0;i < 6;i++)
2870                 {
2871                         // generate an image name based on the base and and suffix
2872                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2873                         // load it
2874                         if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
2875                         {
2876                                 // an image loaded, make sure width and height are equal
2877                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
2878                                 {
2879                                         // if this is the first image to load successfully, allocate the cubemap memory
2880                                         if (!cubemappixels && image_width >= 1)
2881                                         {
2882                                                 cubemapsize = image_width;
2883                                                 // note this clears to black, so unavailable sides are black
2884                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2885                                         }
2886                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2887                                         if (cubemappixels)
2888                                                 Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_buffer, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder);
2889                                 }
2890                                 else
2891                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2892                                 // free the image
2893                                 Mem_Free(image_buffer);
2894                         }
2895                 }
2896         }
2897         // if a cubemap loaded, upload it
2898         if (cubemappixels)
2899         {
2900                 if (developer_loading.integer)
2901                         Con_Printf("loading cubemap \"%s\"\n", basename);
2902
2903                 cubemaptexture = R_LoadTextureCubeMap(r_main_texturepool, basename, cubemapsize, cubemappixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, (gl_texturecompression_lightcubemaps.integer && gl_texturecompression.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
2904                 Mem_Free(cubemappixels);
2905         }
2906         else
2907         {
2908                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
2909                 if (developer_loading.integer)
2910                 {
2911                         Con_Printf("(tried tried images ");
2912                         for (j = 0;j < 3;j++)
2913                                 for (i = 0;i < 6;i++)
2914                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2915                         Con_Print(" and was unable to find any of them).\n");
2916                 }
2917         }
2918         return cubemaptexture;
2919 }
2920
2921 rtexture_t *R_GetCubemap(const char *basename)
2922 {
2923         int i;
2924         for (i = 0;i < r_texture_numcubemaps;i++)
2925                 if (r_texture_cubemaps[i] != NULL)
2926                         if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
2927                                 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
2928         if (i >= MAX_CUBEMAPS || !r_main_mempool)
2929                 return r_texture_whitecube;
2930         r_texture_numcubemaps++;
2931         r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
2932         strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
2933         r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
2934         return r_texture_cubemaps[i]->texture;
2935 }
2936
2937 static void R_Main_FreeViewCache(void)
2938 {
2939         if (r_refdef.viewcache.entityvisible)
2940                 Mem_Free(r_refdef.viewcache.entityvisible);
2941         if (r_refdef.viewcache.world_pvsbits)
2942                 Mem_Free(r_refdef.viewcache.world_pvsbits);
2943         if (r_refdef.viewcache.world_leafvisible)
2944                 Mem_Free(r_refdef.viewcache.world_leafvisible);
2945         if (r_refdef.viewcache.world_surfacevisible)
2946                 Mem_Free(r_refdef.viewcache.world_surfacevisible);
2947         memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
2948 }
2949
2950 static void R_Main_ResizeViewCache(void)
2951 {
2952         int numentities = r_refdef.scene.numentities;
2953         int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
2954         int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
2955         int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
2956         int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
2957         if (r_refdef.viewcache.maxentities < numentities)
2958         {
2959                 r_refdef.viewcache.maxentities = numentities;
2960                 if (r_refdef.viewcache.entityvisible)
2961                         Mem_Free(r_refdef.viewcache.entityvisible);
2962                 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
2963         }
2964         if (r_refdef.viewcache.world_numclusters != numclusters)
2965         {
2966                 r_refdef.viewcache.world_numclusters = numclusters;
2967                 r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
2968                 if (r_refdef.viewcache.world_pvsbits)
2969                         Mem_Free(r_refdef.viewcache.world_pvsbits);
2970                 r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
2971         }
2972         if (r_refdef.viewcache.world_numleafs != numleafs)
2973         {
2974                 r_refdef.viewcache.world_numleafs = numleafs;
2975                 if (r_refdef.viewcache.world_leafvisible)
2976                         Mem_Free(r_refdef.viewcache.world_leafvisible);
2977                 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
2978         }
2979         if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
2980         {
2981                 r_refdef.viewcache.world_numsurfaces = numsurfaces;
2982                 if (r_refdef.viewcache.world_surfacevisible)
2983                         Mem_Free(r_refdef.viewcache.world_surfacevisible);
2984                 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
2985         }
2986 }
2987
2988 extern rtexture_t *loadingscreentexture;
2989 static void gl_main_start(void)
2990 {
2991         loadingscreentexture = NULL;
2992         r_texture_blanknormalmap = NULL;
2993         r_texture_white = NULL;
2994         r_texture_grey128 = NULL;
2995         r_texture_black = NULL;
2996         r_texture_whitecube = NULL;
2997         r_texture_normalizationcube = NULL;
2998         r_texture_fogattenuation = NULL;
2999         r_texture_fogheighttexture = NULL;
3000         r_texture_gammaramps = NULL;
3001         r_texture_numcubemaps = 0;
3002         r_uniformbufferalignment = 32;
3003
3004         r_loaddds = r_texture_dds_load.integer != 0;
3005         r_savedds = vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3006
3007         switch(vid.renderpath)
3008         {
3009         case RENDERPATH_GL32:
3010         case RENDERPATH_GLES2:
3011                 Cvar_SetValueQuick(&r_textureunits, MAX_TEXTUREUNITS);
3012                 Cvar_SetValueQuick(&gl_combine, 1);
3013                 Cvar_SetValueQuick(&r_glsl, 1);
3014                 r_loadnormalmap = true;
3015                 r_loadgloss = true;
3016                 r_loadfog = false;
3017 #ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
3018                 qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
3019 #endif
3020                 break;
3021         }
3022
3023         R_AnimCache_Free();
3024         R_FrameData_Reset();
3025         R_BufferData_Reset();
3026
3027         r_numqueries = 0;
3028         r_maxqueries = 0;
3029         memset(r_queries, 0, sizeof(r_queries));
3030
3031         r_qwskincache = NULL;
3032         r_qwskincache_size = 0;
3033
3034         // due to caching of texture_t references, the collision cache must be reset
3035         Collision_Cache_Reset(true);
3036
3037         // set up r_skinframe loading system for textures
3038         memset(&r_skinframe, 0, sizeof(r_skinframe));
3039         r_skinframe.loadsequence = 1;
3040         Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
3041
3042         r_main_texturepool = R_AllocTexturePool();
3043         R_BuildBlankTextures();
3044         R_BuildNoTexture();
3045         R_BuildWhiteCube();
3046         R_BuildNormalizationCube();
3047         r_texture_fogattenuation = NULL;
3048         r_texture_fogheighttexture = NULL;
3049         r_texture_gammaramps = NULL;
3050         //r_texture_fogintensity = NULL;
3051         memset(&r_fb, 0, sizeof(r_fb));
3052         Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
3053         r_glsl_permutation = NULL;
3054         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3055         Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
3056         memset(&r_svbsp, 0, sizeof (r_svbsp));
3057
3058         memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
3059         r_texture_numcubemaps = 0;
3060
3061         r_refdef.fogmasktable_density = 0;
3062
3063 #ifdef __ANDROID__
3064         // For Steelstorm Android
3065         // FIXME CACHE the program and reload
3066         // FIXME see possible combinations for SS:BR android
3067         Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
3068         R_SetupShader_SetPermutationGLSL(0, 12);
3069         R_SetupShader_SetPermutationGLSL(0, 13);
3070         R_SetupShader_SetPermutationGLSL(0, 8388621);
3071         R_SetupShader_SetPermutationGLSL(3, 0);
3072         R_SetupShader_SetPermutationGLSL(3, 2048);
3073         R_SetupShader_SetPermutationGLSL(5, 0);
3074         R_SetupShader_SetPermutationGLSL(5, 2);
3075         R_SetupShader_SetPermutationGLSL(5, 2048);
3076         R_SetupShader_SetPermutationGLSL(5, 8388608);
3077         R_SetupShader_SetPermutationGLSL(11, 1);
3078         R_SetupShader_SetPermutationGLSL(11, 2049);
3079         R_SetupShader_SetPermutationGLSL(11, 8193);
3080         R_SetupShader_SetPermutationGLSL(11, 10241);
3081         Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
3082 #endif
3083 }
3084
3085 static void gl_main_shutdown(void)
3086 {
3087         R_RenderTarget_FreeUnused(true);
3088         Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
3089         R_AnimCache_Free();
3090         R_FrameData_Reset();
3091         R_BufferData_Reset();
3092
3093         R_Main_FreeViewCache();
3094
3095         switch(vid.renderpath)
3096         {
3097         case RENDERPATH_GL32:
3098         case RENDERPATH_GLES2:
3099 #if defined(GL_SAMPLES_PASSED) && !defined(USE_GLES2)
3100                 if (r_maxqueries)
3101                         qglDeleteQueries(r_maxqueries, r_queries);
3102 #endif
3103                 break;
3104         }
3105
3106         r_numqueries = 0;
3107         r_maxqueries = 0;
3108         memset(r_queries, 0, sizeof(r_queries));
3109
3110         r_qwskincache = NULL;
3111         r_qwskincache_size = 0;
3112
3113         // clear out the r_skinframe state
3114         Mem_ExpandableArray_FreeArray(&r_skinframe.array);
3115         memset(&r_skinframe, 0, sizeof(r_skinframe));
3116
3117         if (r_svbsp.nodes)
3118                 Mem_Free(r_svbsp.nodes);
3119         memset(&r_svbsp, 0, sizeof (r_svbsp));
3120         R_FreeTexturePool(&r_main_texturepool);
3121         loadingscreentexture = NULL;
3122         r_texture_blanknormalmap = NULL;
3123         r_texture_white = NULL;
3124         r_texture_grey128 = NULL;
3125         r_texture_black = NULL;
3126         r_texture_whitecube = NULL;
3127         r_texture_normalizationcube = NULL;
3128         r_texture_fogattenuation = NULL;
3129         r_texture_fogheighttexture = NULL;
3130         r_texture_gammaramps = NULL;
3131         r_texture_numcubemaps = 0;
3132         //r_texture_fogintensity = NULL;
3133         memset(&r_fb, 0, sizeof(r_fb));
3134         R_GLSL_Restart_f(&cmd_client);
3135
3136         r_glsl_permutation = NULL;
3137         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3138         Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
3139 }
3140
3141 static void gl_main_newmap(void)
3142 {
3143         // FIXME: move this code to client
3144         char *entities, entname[MAX_QPATH];
3145         if (r_qwskincache)
3146                 Mem_Free(r_qwskincache);
3147         r_qwskincache = NULL;
3148         r_qwskincache_size = 0;
3149         if (cl.worldmodel)
3150         {
3151                 dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension);
3152                 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
3153                 {
3154                         CL_ParseEntityLump(entities);
3155                         Mem_Free(entities);
3156                         return;
3157                 }
3158                 if (cl.worldmodel->brush.entities)
3159                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
3160         }
3161         R_Main_FreeViewCache();
3162
3163         R_FrameData_Reset();
3164         R_BufferData_Reset();
3165 }
3166
3167 void GL_Main_Init(void)
3168 {
3169         int i;
3170         r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
3171         R_InitShaderModeInfo();
3172
3173         Cmd_AddCommand(&cmd_client, "r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
3174         Cmd_AddCommand(&cmd_client, "r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
3175         // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
3176         if (gamemode == GAME_NEHAHRA)
3177         {
3178                 Cvar_RegisterVariable (&gl_fogenable);
3179                 Cvar_RegisterVariable (&gl_fogdensity);
3180                 Cvar_RegisterVariable (&gl_fogred);
3181                 Cvar_RegisterVariable (&gl_foggreen);
3182                 Cvar_RegisterVariable (&gl_fogblue);
3183                 Cvar_RegisterVariable (&gl_fogstart);
3184                 Cvar_RegisterVariable (&gl_fogend);
3185                 Cvar_RegisterVariable (&gl_skyclip);
3186         }
3187         Cvar_RegisterVariable(&r_motionblur);
3188         Cvar_RegisterVariable(&r_damageblur);
3189         Cvar_RegisterVariable(&r_motionblur_averaging);
3190         Cvar_RegisterVariable(&r_motionblur_randomize);
3191         Cvar_RegisterVariable(&r_motionblur_minblur);
3192         Cvar_RegisterVariable(&r_motionblur_maxblur);
3193         Cvar_RegisterVariable(&r_motionblur_velocityfactor);
3194         Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed);
3195         Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed);
3196         Cvar_RegisterVariable(&r_motionblur_mousefactor);
3197         Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed);
3198         Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed);
3199         Cvar_RegisterVariable(&r_depthfirst);
3200         Cvar_RegisterVariable(&r_useinfinitefarclip);
3201         Cvar_RegisterVariable(&r_farclip_base);
3202         Cvar_RegisterVariable(&r_farclip_world);
3203         Cvar_RegisterVariable(&r_nearclip);
3204         Cvar_RegisterVariable(&r_deformvertexes);
3205         Cvar_RegisterVariable(&r_transparent);
3206         Cvar_RegisterVariable(&r_transparent_alphatocoverage);
3207         Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
3208         Cvar_RegisterVariable(&r_transparent_useplanardistance);
3209         Cvar_RegisterVariable(&r_showoverdraw);
3210         Cvar_RegisterVariable(&r_showbboxes);
3211         Cvar_RegisterVariable(&r_showbboxes_client);
3212         Cvar_RegisterVariable(&r_showsurfaces);
3213         Cvar_RegisterVariable(&r_showtris);
3214         Cvar_RegisterVariable(&r_shownormals);
3215         Cvar_RegisterVariable(&r_showlighting);
3216         Cvar_RegisterVariable(&r_showcollisionbrushes);
3217         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
3218         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
3219         Cvar_RegisterVariable(&r_showdisabledepthtest);
3220         Cvar_RegisterVariable(&r_showspriteedges);
3221         Cvar_RegisterVariable(&r_showparticleedges);
3222         Cvar_RegisterVariable(&r_drawportals);
3223         Cvar_RegisterVariable(&r_drawentities);
3224         Cvar_RegisterVariable(&r_draw2d);
3225         Cvar_RegisterVariable(&r_drawworld);
3226         Cvar_RegisterVariable(&r_cullentities_trace);
3227         Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
3228         Cvar_RegisterVariable(&r_cullentities_trace_samples);
3229         Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
3230         Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
3231         Cvar_RegisterVariable(&r_cullentities_trace_expand);
3232         Cvar_RegisterVariable(&r_cullentities_trace_pad);
3233         Cvar_RegisterVariable(&r_cullentities_trace_delay);
3234         Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
3235         Cvar_RegisterVariable(&r_sortentities);
3236         Cvar_RegisterVariable(&r_drawviewmodel);
3237         Cvar_RegisterVariable(&r_drawexteriormodel);
3238         Cvar_RegisterVariable(&r_speeds);
3239         Cvar_RegisterVariable(&r_fullbrights);
3240         Cvar_RegisterVariable(&r_wateralpha);
3241         Cvar_RegisterVariable(&r_dynamic);
3242         Cvar_RegisterVariable(&r_fullbright_directed);
3243         Cvar_RegisterVariable(&r_fullbright_directed_ambient);
3244         Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
3245         Cvar_RegisterVariable(&r_fullbright_directed_pitch);
3246         Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
3247         Cvar_RegisterVariable(&r_fullbright);
3248         Cvar_RegisterVariable(&r_shadows);
3249         Cvar_RegisterVariable(&r_shadows_darken);
3250         Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
3251         Cvar_RegisterVariable(&r_shadows_castfrombmodels);
3252         Cvar_RegisterVariable(&r_shadows_throwdistance);
3253         Cvar_RegisterVariable(&r_shadows_throwdirection);
3254         Cvar_RegisterVariable(&r_shadows_focus);
3255         Cvar_RegisterVariable(&r_shadows_shadowmapscale);
3256         Cvar_RegisterVariable(&r_shadows_shadowmapbias);
3257         Cvar_RegisterVariable(&r_q1bsp_skymasking);
3258         Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
3259         Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
3260         Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
3261         Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
3262         Cvar_RegisterVariable(&r_fog_exp2);
3263         Cvar_RegisterVariable(&r_fog_clear);
3264         Cvar_RegisterVariable(&r_drawfog);
3265         Cvar_RegisterVariable(&r_transparentdepthmasking);
3266         Cvar_RegisterVariable(&r_transparent_sortmindist);
3267         Cvar_RegisterVariable(&r_transparent_sortmaxdist);
3268         Cvar_RegisterVariable(&r_transparent_sortarraysize);
3269         Cvar_RegisterVariable(&r_texture_dds_load);
3270         Cvar_RegisterVariable(&r_texture_dds_save);
3271         Cvar_RegisterVariable(&r_textureunits);
3272         Cvar_RegisterVariable(&gl_combine);
3273         Cvar_RegisterVariable(&r_usedepthtextures);
3274         Cvar_RegisterVariable(&r_viewfbo);
3275         Cvar_RegisterVariable(&r_rendertarget_debug);
3276         Cvar_RegisterVariable(&r_viewscale);
3277         Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3278         Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3279         Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3280         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3281         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3282         Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3283         Cvar_RegisterVariable(&r_glsl);
3284         Cvar_RegisterVariable(&r_glsl_deluxemapping);
3285         Cvar_RegisterVariable(&r_glsl_offsetmapping);
3286         Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3287         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3288         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3289         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3290         Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3291         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3292         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3293         Cvar_RegisterVariable(&r_glsl_postprocess);
3294         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3295         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3296         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3297         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3298         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3299         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3300         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3301         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3302         Cvar_RegisterVariable(&r_celshading);
3303         Cvar_RegisterVariable(&r_celoutlines);
3304
3305         Cvar_RegisterVariable(&r_water);
3306         Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3307         Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3308         Cvar_RegisterVariable(&r_water_clippingplanebias);
3309         Cvar_RegisterVariable(&r_water_refractdistort);
3310         Cvar_RegisterVariable(&r_water_reflectdistort);
3311         Cvar_RegisterVariable(&r_water_scissormode);
3312         Cvar_RegisterVariable(&r_water_lowquality);
3313         Cvar_RegisterVariable(&r_water_hideplayer);
3314
3315         Cvar_RegisterVariable(&r_lerpsprites);
3316         Cvar_RegisterVariable(&r_lerpmodels);
3317         Cvar_RegisterVariable(&r_lerplightstyles);
3318         Cvar_RegisterVariable(&r_waterscroll);
3319         Cvar_RegisterVariable(&r_bloom);
3320         Cvar_RegisterVariable(&r_bloom_colorscale);
3321         Cvar_RegisterVariable(&r_bloom_brighten);
3322         Cvar_RegisterVariable(&r_bloom_blur);
3323         Cvar_RegisterVariable(&r_bloom_resolution);
3324         Cvar_RegisterVariable(&r_bloom_colorexponent);
3325         Cvar_RegisterVariable(&r_bloom_colorsubtract);
3326         Cvar_RegisterVariable(&r_bloom_scenebrightness);
3327         Cvar_RegisterVariable(&r_hdr_scenebrightness);
3328         Cvar_RegisterVariable(&r_hdr_glowintensity);
3329         Cvar_RegisterVariable(&r_hdr_irisadaptation);
3330         Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3331         Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3332         Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3333         Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3334         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3335         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3336         Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3337         Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3338         Cvar_RegisterVariable(&developer_texturelogging);
3339         Cvar_RegisterVariable(&gl_lightmaps);
3340         Cvar_RegisterVariable(&r_test);
3341         Cvar_RegisterVariable(&r_batch_multidraw);
3342         Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3343         Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3344         Cvar_RegisterVariable(&r_glsl_skeletal);
3345         Cvar_RegisterVariable(&r_glsl_saturation);
3346         Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3347         Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3348         Cvar_RegisterVariable(&r_framedatasize);
3349         for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3350                 Cvar_RegisterVariable(&r_buffermegs[i]);
3351         Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3352         if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3353                 Cvar_SetValue(&cvars_all, "r_fullbrights", 0);
3354 #ifdef DP_MOBILETOUCH
3355         // GLES devices have terrible depth precision in general, so...
3356         Cvar_SetValueQuick(&r_nearclip, 4);
3357         Cvar_SetValueQuick(&r_farclip_base, 4096);
3358         Cvar_SetValueQuick(&r_farclip_world, 0);
3359         Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3360 #endif
3361         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3362 }
3363
3364 void Render_Init(void)
3365 {
3366         gl_backend_init();
3367         R_Textures_Init();
3368         GL_Main_Init();
3369         Font_Init();
3370         GL_Draw_Init();
3371         R_Shadow_Init();
3372         R_Sky_Init();
3373         GL_Surf_Init();
3374         Sbar_Init();
3375         R_Particles_Init();
3376         R_Explosion_Init();
3377         R_LightningBeams_Init();
3378         Mod_RenderInit();
3379 }
3380
3381 int R_CullBox(const vec3_t mins, const vec3_t maxs)
3382 {
3383         int i;
3384         mplane_t *p;
3385         if (r_trippy.integer)
3386                 return false;
3387         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
3388         {
3389                 p = r_refdef.view.frustum + i;
3390                 switch(p->signbits)
3391                 {
3392                 default:
3393                 case 0:
3394                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3395                                 return true;
3396                         break;
3397                 case 1:
3398                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3399                                 return true;
3400                         break;
3401                 case 2:
3402                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3403                                 return true;
3404                         break;
3405                 case 3:
3406                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3407                                 return true;
3408                         break;
3409                 case 4:
3410                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3411                                 return true;
3412                         break;
3413                 case 5:
3414                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3415                                 return true;
3416                         break;
3417                 case 6:
3418                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3419                                 return true;
3420                         break;
3421                 case 7:
3422                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3423                                 return true;
3424                         break;
3425                 }
3426         }
3427         return false;
3428 }
3429
3430 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3431 {
3432         int i;
3433         const mplane_t *p;
3434         if (r_trippy.integer)
3435                 return false;
3436         for (i = 0;i < numplanes;i++)
3437         {
3438                 p = planes + i;
3439                 switch(p->signbits)
3440                 {
3441                 default:
3442                 case 0:
3443                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3444                                 return true;
3445                         break;
3446                 case 1:
3447                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3448                                 return true;
3449                         break;
3450                 case 2:
3451                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3452                                 return true;
3453                         break;
3454                 case 3:
3455                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3456                                 return true;
3457                         break;
3458                 case 4:
3459                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3460                                 return true;
3461                         break;
3462                 case 5:
3463                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3464                                 return true;
3465                         break;
3466                 case 6:
3467                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3468                                 return true;
3469                         break;
3470                 case 7:
3471                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3472                                 return true;
3473                         break;
3474                 }
3475         }
3476         return false;
3477 }
3478
3479 //==================================================================================
3480
3481 // LadyHavoc: this stores temporary data used within the same frame
3482
3483 typedef struct r_framedata_mem_s
3484 {
3485         struct r_framedata_mem_s *purge; // older mem block to free on next frame
3486         size_t size; // how much usable space
3487         size_t current; // how much space in use
3488         size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3489         size_t wantedsize; // how much space was allocated
3490         unsigned char *data; // start of real data (16byte aligned)
3491 }
3492 r_framedata_mem_t;
3493
3494 static r_framedata_mem_t *r_framedata_mem;
3495
3496 void R_FrameData_Reset(void)
3497 {
3498         while (r_framedata_mem)
3499         {
3500                 r_framedata_mem_t *next = r_framedata_mem->purge;
3501                 Mem_Free(r_framedata_mem);
3502                 r_framedata_mem = next;
3503         }
3504 }
3505
3506 static void R_FrameData_Resize(qboolean mustgrow)
3507 {
3508         size_t wantedsize;
3509         wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3510         wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3511         if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3512         {
3513                 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3514                 newmem->wantedsize = wantedsize;
3515                 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3516                 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3517                 newmem->current = 0;
3518                 newmem->mark = 0;
3519                 newmem->purge = r_framedata_mem;
3520                 r_framedata_mem = newmem;
3521         }
3522 }
3523
3524 void R_FrameData_NewFrame(void)
3525 {
3526         R_FrameData_Resize(false);
3527         if (!r_framedata_mem)
3528                 return;
3529         // if we ran out of space on the last frame, free the old memory now
3530         while (r_framedata_mem->purge)
3531         {
3532                 // repeatedly remove the second item in the list, leaving only head
3533                 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3534                 Mem_Free(r_framedata_mem->purge);
3535                 r_framedata_mem->purge = next;
3536         }
3537         // reset the current mem pointer
3538         r_framedata_mem->current = 0;
3539         r_framedata_mem->mark = 0;
3540 }
3541
3542 void *R_FrameData_Alloc(size_t size)
3543 {
3544         void *data;
3545         float newvalue;
3546
3547         // align to 16 byte boundary - the data pointer is already aligned, so we
3548         // only need to ensure the size of every allocation is also aligned
3549         size = (size + 15) & ~15;
3550
3551         while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3552         {
3553                 // emergency - we ran out of space, allocate more memory
3554                 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3555                 newvalue = r_framedatasize.value * 2.0f;
3556                 // upper bound based on architecture - if we try to allocate more than this we could overflow, better to loop until we error out on allocation failure
3557                 if (sizeof(size_t) >= 8)
3558                         newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3559                 else
3560                         newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3561                 // this might not be a growing it, but we'll allocate another buffer every time
3562                 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3563                 R_FrameData_Resize(true);
3564         }
3565
3566         data = r_framedata_mem->data + r_framedata_mem->current;
3567         r_framedata_mem->current += size;
3568
3569         // count the usage for stats
3570         r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3571         r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3572
3573         return (void *)data;
3574 }
3575
3576 void *R_FrameData_Store(size_t size, void *data)
3577 {
3578         void *d = R_FrameData_Alloc(size);
3579         if (d && data)
3580                 memcpy(d, data, size);
3581         return d;
3582 }
3583
3584 void R_FrameData_SetMark(void)
3585 {
3586         if (!r_framedata_mem)
3587                 return;
3588         r_framedata_mem->mark = r_framedata_mem->current;
3589 }
3590
3591 void R_FrameData_ReturnToMark(void)
3592 {
3593         if (!r_framedata_mem)
3594                 return;
3595         r_framedata_mem->current = r_framedata_mem->mark;
3596 }
3597
3598 //==================================================================================
3599
3600 // avoid reusing the same buffer objects on consecutive frames
3601 #define R_BUFFERDATA_CYCLE 3
3602
3603 typedef struct r_bufferdata_buffer_s
3604 {
3605         struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3606         size_t size; // how much usable space
3607         size_t current; // how much space in use
3608         r_meshbuffer_t *buffer; // the buffer itself
3609 }
3610 r_bufferdata_buffer_t;
3611
3612 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3613 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3614
3615 /// frees all dynamic buffers
3616 void R_BufferData_Reset(void)
3617 {
3618         int cycle, type;
3619         r_bufferdata_buffer_t **p, *mem;
3620         for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3621         {
3622                 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3623                 {
3624                         // free all buffers
3625                         p = &r_bufferdata_buffer[cycle][type];
3626                         while (*p)
3627                         {
3628                                 mem = *p;
3629                                 *p = (*p)->purge;
3630                                 if (mem->buffer)
3631                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3632                                 Mem_Free(mem);
3633                         }
3634                 }
3635         }
3636 }
3637
3638 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3639 static void R_BufferData_Resize(r_bufferdata_type_t type, qboolean mustgrow, size_t minsize)
3640 {
3641         r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3642         size_t size;
3643         float newvalue = r_buffermegs[type].value;
3644
3645         // increase the cvar if we have to (but only if we already have a mem)
3646         if (mustgrow && mem)
3647                 newvalue *= 2.0f;
3648         newvalue = bound(0.25f, newvalue, 256.0f);
3649         while (newvalue * 1024*1024 < minsize)
3650                 newvalue *= 2.0f;
3651
3652         // clamp the cvar to valid range
3653         newvalue = bound(0.25f, newvalue, 256.0f);
3654         if (r_buffermegs[type].value != newvalue)
3655                 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3656
3657         // calculate size in bytes
3658         size = (size_t)(newvalue * 1024*1024);
3659         size = bound(131072, size, 256*1024*1024);
3660
3661         // allocate a new buffer if the size is different (purge old one later)
3662         // or if we were told we must grow the buffer
3663         if (!mem || mem->size != size || mustgrow)
3664         {
3665                 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3666                 mem->size = size;
3667                 mem->current = 0;
3668                 if (type == R_BUFFERDATA_VERTEX)
3669                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3670                 else if (type == R_BUFFERDATA_INDEX16)
3671                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3672                 else if (type == R_BUFFERDATA_INDEX32)
3673                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3674                 else if (type == R_BUFFERDATA_UNIFORM)
3675                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3676                 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3677                 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3678         }
3679 }
3680
3681 void R_BufferData_NewFrame(void)
3682 {
3683         int type;
3684         r_bufferdata_buffer_t **p, *mem;
3685         // cycle to the next frame's buffers
3686         r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3687         // if we ran out of space on the last time we used these buffers, free the old memory now
3688         for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3689         {
3690                 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3691                 {
3692                         R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3693                         // free all but the head buffer, this is how we recycle obsolete
3694                         // buffers after they are no longer in use
3695                         p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3696                         while (*p)
3697                         {
3698                                 mem = *p;
3699                                 *p = (*p)->purge;
3700                                 if (mem->buffer)
3701                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3702                                 Mem_Free(mem);
3703                         }
3704                         // reset the current offset
3705                         r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3706                 }
3707         }
3708 }
3709
3710 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3711 {
3712         r_bufferdata_buffer_t *mem;
3713         int offset = 0;
3714         int padsize;
3715
3716         *returnbufferoffset = 0;
3717
3718         // align size to a byte boundary appropriate for the buffer type, this
3719         // makes all allocations have aligned start offsets
3720         if (type == R_BUFFERDATA_UNIFORM)
3721                 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3722         else
3723                 padsize = (datasize + 15) & ~15;
3724
3725         // if we ran out of space in this buffer we must allocate a new one
3726         if (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size)
3727                 R_BufferData_Resize(type, true, padsize);
3728
3729         // if the resize did not give us enough memory, fail
3730         if (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size)
3731                 Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3732
3733         mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3734         offset = (int)mem->current;
3735         mem->current += padsize;
3736
3737         // upload the data to the buffer at the chosen offset
3738         if (offset == 0)
3739                 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3740         R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3741
3742         // count the usage for stats
3743         r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3744         r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3745
3746         // return the buffer offset
3747         *returnbufferoffset = offset;
3748
3749         return mem->buffer;
3750 }
3751
3752 //==================================================================================
3753
3754 // LadyHavoc: animcache originally written by Echon, rewritten since then
3755
3756 /**
3757  * Animation cache prevents re-generating mesh data for an animated model
3758  * multiple times in one frame for lighting, shadowing, reflections, etc.
3759  */
3760
3761 void R_AnimCache_Free(void)
3762 {
3763 }
3764
3765 void R_AnimCache_ClearCache(void)
3766 {
3767         int i;
3768         entity_render_t *ent;
3769
3770         for (i = 0;i < r_refdef.scene.numentities;i++)
3771         {
3772                 ent = r_refdef.scene.entities[i];
3773                 ent->animcache_vertex3f = NULL;
3774                 ent->animcache_vertex3f_vertexbuffer = NULL;
3775                 ent->animcache_vertex3f_bufferoffset = 0;
3776                 ent->animcache_normal3f = NULL;
3777                 ent->animcache_normal3f_vertexbuffer = NULL;
3778                 ent->animcache_normal3f_bufferoffset = 0;
3779                 ent->animcache_svector3f = NULL;
3780                 ent->animcache_svector3f_vertexbuffer = NULL;
3781                 ent->animcache_svector3f_bufferoffset = 0;
3782                 ent->animcache_tvector3f = NULL;
3783                 ent->animcache_tvector3f_vertexbuffer = NULL;
3784                 ent->animcache_tvector3f_bufferoffset = 0;
3785                 ent->animcache_skeletaltransform3x4 = NULL;
3786                 ent->animcache_skeletaltransform3x4buffer = NULL;
3787                 ent->animcache_skeletaltransform3x4offset = 0;
3788                 ent->animcache_skeletaltransform3x4size = 0;
3789         }
3790 }
3791
3792 qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
3793 {
3794         dp_model_t *model = ent->model;
3795         int numvertices;
3796
3797         // see if this ent is worth caching
3798         if (!model || !model->Draw || !model->AnimateVertices)
3799                 return false;
3800         // nothing to cache if it contains no animations and has no skeleton
3801         if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3802                 return false;
3803         // see if it is already cached for gpuskeletal
3804         if (ent->animcache_skeletaltransform3x4)
3805                 return false;
3806         // see if it is already cached as a mesh
3807         if (ent->animcache_vertex3f)
3808         {
3809                 // check if we need to add normals or tangents
3810                 if (ent->animcache_normal3f)
3811                         wantnormals = false;
3812                 if (ent->animcache_svector3f)
3813                         wanttangents = false;
3814                 if (!wantnormals && !wanttangents)
3815                         return false;
3816         }
3817
3818         // check which kind of cache we need to generate
3819         if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3820         {
3821                 // cache the skeleton so the vertex shader can use it
3822                 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3823                 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3824                 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3825                 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3826                 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4); 
3827                 // note: this can fail if the buffer is at the grow limit
3828                 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3829                 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3830         }
3831         else if (ent->animcache_vertex3f)
3832         {
3833                 // mesh was already cached but we may need to add normals/tangents
3834                 // (this only happens with multiple views, reflections, cameras, etc)
3835                 if (wantnormals || wanttangents)
3836                 {
3837                         numvertices = model->surfmesh.num_vertices;
3838                         if (wantnormals)
3839                                 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3840                         if (wanttangents)
3841                         {
3842                                 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3843                                 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3844                         }
3845                         model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3846                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3847                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3848                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3849                 }
3850         }
3851         else
3852         {
3853                 // generate mesh cache
3854                 numvertices = model->surfmesh.num_vertices;
3855                 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3856                 if (wantnormals)
3857                         ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3858                 if (wanttangents)
3859                 {
3860                         ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3861                         ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3862                 }
3863                 model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
3864                 if (wantnormals || wanttangents)
3865                 {
3866                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3867                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3868                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3869                 }
3870                 r_refdef.stats[r_stat_animcache_shape_count] += 1;
3871                 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
3872                 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
3873         }
3874         return true;
3875 }
3876
3877 void R_AnimCache_CacheVisibleEntities(void)
3878 {
3879         int i;
3880
3881         // TODO: thread this
3882         // NOTE: R_PrepareRTLights() also caches entities
3883
3884         for (i = 0;i < r_refdef.scene.numentities;i++)
3885                 if (r_refdef.viewcache.entityvisible[i])
3886                         R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
3887 }
3888
3889 //==================================================================================
3890
3891 qboolean R_CanSeeBox(int numsamples, vec_t eyejitter, vec_t entboxenlarge, vec_t entboxexpand, vec_t pad, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs)
3892 {
3893         int i;
3894         vec3_t eyemins, eyemaxs;
3895         vec3_t boxmins, boxmaxs;
3896         vec3_t padmins, padmaxs;
3897         vec3_t start;
3898         vec3_t end;
3899         dp_model_t *model = r_refdef.scene.worldmodel;
3900         static vec3_t positions[] = {
3901                 { 0.5f, 0.5f, 0.5f },
3902                 { 0.0f, 0.0f, 0.0f },
3903                 { 0.0f, 0.0f, 1.0f },
3904                 { 0.0f, 1.0f, 0.0f },
3905                 { 0.0f, 1.0f, 1.0f },
3906                 { 1.0f, 0.0f, 0.0f },
3907                 { 1.0f, 0.0f, 1.0f },
3908                 { 1.0f, 1.0f, 0.0f },
3909                 { 1.0f, 1.0f, 1.0f },
3910         };
3911
3912         // sample count can be set to -1 to skip this logic, for flicker-prone objects
3913         if (numsamples < 0)
3914                 return true;
3915
3916         // view origin is not used for culling in portal/reflection/refraction renders or isometric views
3917         if (!r_refdef.view.usevieworiginculling)
3918                 return true;
3919
3920         if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
3921                 return true;
3922
3923         // expand the eye box a little
3924         eyemins[0] = eye[0] - eyejitter;
3925         eyemaxs[0] = eye[0] + eyejitter;
3926         eyemins[1] = eye[1] - eyejitter;
3927         eyemaxs[1] = eye[1] + eyejitter;
3928         eyemins[2] = eye[2] - eyejitter;
3929         eyemaxs[2] = eye[2] + eyejitter;
3930         // expand the box a little
3931         boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
3932         boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
3933         boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
3934         boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
3935         boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
3936         boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
3937         // make an even larger box for the acceptable area
3938         padmins[0] = boxmins[0] - pad;
3939         padmaxs[0] = boxmaxs[0] + pad;
3940         padmins[1] = boxmins[1] - pad;
3941         padmaxs[1] = boxmaxs[1] + pad;
3942         padmins[2] = boxmins[2] - pad;
3943         padmaxs[2] = boxmaxs[2] + pad;
3944
3945         // return true if eye overlaps enlarged box
3946         if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
3947                 return true;
3948
3949         // try specific positions in the box first - note that these can be cached
3950         if (r_cullentities_trace_entityocclusion.integer)
3951         {
3952                 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
3953                 {
3954                         VectorCopy(eye, start);
3955                         end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
3956                         end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
3957                         end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
3958                         //trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
3959                         trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
3960                         // not picky - if the trace ended anywhere in the box we're good
3961                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
3962                                 return true;
3963                 }
3964         }
3965         else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
3966                 return true;
3967
3968         // try various random positions
3969         for (i = 0; i < numsamples; i++)
3970         {
3971                 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
3972                 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
3973                 if (r_cullentities_trace_entityocclusion.integer)
3974                 {
3975                         trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
3976                         // not picky - if the trace ended anywhere in the box we're good
3977                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
3978                                 return true;
3979                 }
3980                 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
3981                         return true;
3982         }
3983
3984         return false;
3985 }
3986
3987
3988 static void R_View_UpdateEntityVisible (void)
3989 {
3990         int i;
3991         int renderimask;
3992         int samples;
3993         entity_render_t *ent;
3994
3995         if (r_refdef.envmap || r_fb.water.hideplayer)
3996                 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
3997         else if (chase_active.integer || r_fb.water.renderingscene)
3998                 renderimask = RENDER_VIEWMODEL;
3999         else
4000                 renderimask = RENDER_EXTERIORMODEL;
4001         if (!r_drawviewmodel.integer)
4002                 renderimask |= RENDER_VIEWMODEL;
4003         if (!r_drawexteriormodel.integer)
4004                 renderimask |= RENDER_EXTERIORMODEL;
4005         memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4006         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4007         {
4008                 // worldmodel can check visibility
4009                 for (i = 0;i < r_refdef.scene.numentities;i++)
4010                 {
4011                         ent = r_refdef.scene.entities[i];
4012                         if (!(ent->flags & renderimask))
4013                         if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
4014                         if ((ent->flags & (RENDER_NODEPTHTEST | RENDER_WORLDOBJECT | RENDER_VIEWMODEL)) || r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, ent->mins, ent->maxs))
4015                                 r_refdef.viewcache.entityvisible[i] = true;
4016                 }
4017         }
4018         else
4019         {
4020                 // no worldmodel or it can't check visibility
4021                 for (i = 0;i < r_refdef.scene.numentities;i++)
4022                 {
4023                         ent = r_refdef.scene.entities[i];
4024                         if (!(ent->flags & renderimask))
4025                         if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
4026                                 r_refdef.viewcache.entityvisible[i] = true;
4027                 }
4028         }
4029         if (r_cullentities_trace.integer)
4030         {
4031                 for (i = 0;i < r_refdef.scene.numentities;i++)
4032                 {
4033                         if (!r_refdef.viewcache.entityvisible[i])
4034                                 continue;
4035                         ent = r_refdef.scene.entities[i];
4036                         if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4037                         {
4038                                 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4039                                 if (R_CanSeeBox(samples, r_cullentities_trace_eyejitter.value, r_cullentities_trace_enlarge.value, r_cullentities_trace_expand.value, r_cullentities_trace_pad.value, r_refdef.view.origin, ent->mins, ent->maxs))
4040                                         ent->last_trace_visibility = realtime;
4041                                 if (ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
4042                                         r_refdef.viewcache.entityvisible[i] = 0;
4043                         }
4044                 }
4045         }
4046 }
4047
4048 /// only used if skyrendermasked, and normally returns false
4049 static int R_DrawBrushModelsSky (void)
4050 {
4051         int i, sky;
4052         entity_render_t *ent;
4053
4054         sky = false;
4055         for (i = 0;i < r_refdef.scene.numentities;i++)
4056         {
4057                 if (!r_refdef.viewcache.entityvisible[i])
4058                         continue;
4059                 ent = r_refdef.scene.entities[i];
4060                 if (!ent->model || !ent->model->DrawSky)
4061                         continue;
4062                 ent->model->DrawSky(ent);
4063                 sky = true;
4064         }
4065         return sky;
4066 }
4067
4068 static void R_DrawNoModel(entity_render_t *ent);
4069 static void R_DrawModels(void)
4070 {
4071         int i;
4072         entity_render_t *ent;
4073
4074         for (i = 0;i < r_refdef.scene.numentities;i++)
4075         {
4076                 if (!r_refdef.viewcache.entityvisible[i])
4077                         continue;
4078                 ent = r_refdef.scene.entities[i];
4079                 r_refdef.stats[r_stat_entities]++;
4080                 /*
4081                 if (ent->model && !strncmp(ent->model->name, "models/proto_", 13))
4082                 {
4083                         vec3_t f, l, u, o;
4084                         Matrix4x4_ToVectors(&ent->matrix, f, l, u, o);
4085                         Con_Printf("R_DrawModels\n");
4086                         Con_Printf("model %s O %f %f %f F %f %f %f L %f %f %f U %f %f %f\n", ent->model->name, o[0], o[1], o[2], f[0], f[1], f[2], l[0], l[1], l[2], u[0], u[1], u[2]);
4087                         Con_Printf("group: %i %f %i %f %i %f %i %f\n", ent->framegroupblend[0].frame, ent->framegroupblend[0].lerp, ent->framegroupblend[1].frame, ent->framegroupblend[1].lerp, ent->framegroupblend[2].frame, ent->framegroupblend[2].lerp, ent->framegroupblend[3].frame, ent->framegroupblend[3].lerp);
4088                         Con_Printf("blend: %i %f %i %f %i %f %i %f %i %f %i %f %i %f %i %f\n", ent->frameblend[0].subframe, ent->frameblend[0].lerp, ent->frameblend[1].subframe, ent->frameblend[1].lerp, ent->frameblend[2].subframe, ent->frameblend[2].lerp, ent->frameblend[3].subframe, ent->frameblend[3].lerp, ent->frameblend[4].subframe, ent->frameblend[4].lerp, ent->frameblend[5].subframe, ent->frameblend[5].lerp, ent->frameblend[6].subframe, ent->frameblend[6].lerp, ent->frameblend[7].subframe, ent->frameblend[7].lerp);
4089                 }
4090                 */
4091                 if (ent->model && ent->model->Draw != NULL)
4092                         ent->model->Draw(ent);
4093                 else
4094                         R_DrawNoModel(ent);
4095         }
4096 }
4097
4098 static void R_DrawModelsDepth(void)
4099 {
4100         int i;
4101         entity_render_t *ent;
4102
4103         for (i = 0;i < r_refdef.scene.numentities;i++)
4104         {
4105                 if (!r_refdef.viewcache.entityvisible[i])
4106                         continue;
4107                 ent = r_refdef.scene.entities[i];
4108                 if (ent->model && ent->model->DrawDepth != NULL)
4109                         ent->model->DrawDepth(ent);
4110         }
4111 }
4112
4113 static void R_DrawModelsDebug(void)
4114 {
4115         int i;
4116         entity_render_t *ent;
4117
4118         for (i = 0;i < r_refdef.scene.numentities;i++)
4119         {
4120                 if (!r_refdef.viewcache.entityvisible[i])
4121                         continue;
4122                 ent = r_refdef.scene.entities[i];
4123                 if (ent->model && ent->model->DrawDebug != NULL)
4124                         ent->model->DrawDebug(ent);
4125         }
4126 }
4127
4128 static void R_DrawModelsAddWaterPlanes(void)
4129 {
4130         int i;
4131         entity_render_t *ent;
4132
4133         for (i = 0;i < r_refdef.scene.numentities;i++)
4134         {
4135                 if (!r_refdef.viewcache.entityvisible[i])
4136                         continue;
4137                 ent = r_refdef.scene.entities[i];
4138                 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4139                         ent->model->DrawAddWaterPlanes(ent);
4140         }
4141 }
4142
4143 static float irisvecs[7][3] = {{0, 0, 0}, {-1, 0, 0}, {1, 0, 0}, {0, -1, 0}, {0, 1, 0}, {0, 0, -1}, {0, 0, 1}};
4144
4145 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4146 {
4147         if (r_hdr_irisadaptation.integer)
4148         {
4149                 vec3_t p;
4150                 vec3_t ambient;
4151                 vec3_t diffuse;
4152                 vec3_t diffusenormal;
4153                 vec3_t forward;
4154                 vec_t brightness = 0.0f;
4155                 vec_t goal;
4156                 vec_t current;
4157                 vec_t d;
4158                 int c;
4159                 VectorCopy(r_refdef.view.forward, forward);
4160                 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4161                 {
4162                         p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4163                         p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4164                         p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4165                         R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4166                         d = DotProduct(forward, diffusenormal);
4167                         brightness += VectorLength(ambient);
4168                         if (d > 0)
4169                                 brightness += d * VectorLength(diffuse);
4170                 }
4171                 brightness *= 1.0f / c;
4172                 brightness += 0.00001f; // make sure it's never zero
4173                 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4174                 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4175                 current = r_hdr_irisadaptation_value.value;
4176                 if (current < goal)
4177                         current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4178                 else if (current > goal)
4179                         current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4180                 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4181                         Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4182         }
4183         else if (r_hdr_irisadaptation_value.value != 1.0f)
4184                 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4185 }
4186
4187 static void R_View_SetFrustum(const int *scissor)
4188 {
4189         int i;
4190         double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4191         vec3_t forward, left, up, origin, v;
4192
4193         if(scissor)
4194         {
4195                 // flipped x coordinates (because x points left here)
4196                 fpx =  1.0 - 2.0 * (scissor[0]              - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4197                 fnx =  1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4198                 // non-flipped y coordinates
4199                 fny = -1.0 + 2.0 * (scissor[1]              - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4200                 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4201         }
4202
4203         // we can't trust r_refdef.view.forward and friends in reflected scenes
4204         Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4205
4206 #if 0
4207         r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4208         r_refdef.view.frustum[0].normal[1] = 0 - 0;
4209         r_refdef.view.frustum[0].normal[2] = -1 - 0;
4210         r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4211         r_refdef.view.frustum[1].normal[1] = 0 + 0;
4212         r_refdef.view.frustum[1].normal[2] = -1 + 0;
4213         r_refdef.view.frustum[2].normal[0] = 0 - 0;
4214         r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4215         r_refdef.view.frustum[2].normal[2] = -1 - 0;
4216         r_refdef.view.frustum[3].normal[0] = 0 + 0;
4217         r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4218         r_refdef.view.frustum[3].normal[2] = -1 + 0;
4219 #endif
4220
4221 #if 0
4222         zNear = r_refdef.nearclip;
4223         nudge = 1.0 - 1.0 / (1<<23);
4224         r_refdef.view.frustum[4].normal[0] = 0 - 0;
4225         r_refdef.view.frustum[4].normal[1] = 0 - 0;
4226         r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4227         r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4228         r_refdef.view.frustum[5].normal[0] = 0 + 0;
4229         r_refdef.view.frustum[5].normal[1] = 0 + 0;
4230         r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4231         r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4232 #endif
4233
4234
4235
4236 #if 0
4237         r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4238         r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4239         r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4240         r_refdef.view.frustum[0].dist = m[15] - m[12];
4241
4242         r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4243         r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4244         r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4245         r_refdef.view.frustum[1].dist = m[15] + m[12];
4246
4247         r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4248         r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4249         r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4250         r_refdef.view.frustum[2].dist = m[15] - m[13];
4251
4252         r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4253         r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4254         r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4255         r_refdef.view.frustum[3].dist = m[15] + m[13];
4256
4257         r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4258         r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4259         r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4260         r_refdef.view.frustum[4].dist = m[15] - m[14];
4261
4262         r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4263         r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4264         r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4265         r_refdef.view.frustum[5].dist = m[15] + m[14];
4266 #endif
4267
4268         if (r_refdef.view.useperspective)
4269         {
4270                 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4271                 VectorMAMAM(1024, forward, fnx * 1024.0 * r_refdef.view.frustum_x, left, fny * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[0]);
4272                 VectorMAMAM(1024, forward, fpx * 1024.0 * r_refdef.view.frustum_x, left, fny * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[1]);
4273                 VectorMAMAM(1024, forward, fnx * 1024.0 * r_refdef.view.frustum_x, left, fpy * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[2]);
4274                 VectorMAMAM(1024, forward, fpx * 1024.0 * r_refdef.view.frustum_x, left, fpy * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[3]);
4275
4276                 // then the normals from the corners relative to origin
4277                 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4278                 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4279                 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4280                 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4281
4282                 // in a NORMAL view, forward cross left == up
4283                 // in a REFLECTED view, forward cross left == down
4284                 // so our cross products above need to be adjusted for a left handed coordinate system
4285                 CrossProduct(forward, left, v);
4286                 if(DotProduct(v, up) < 0)
4287                 {
4288                         VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4289                         VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4290                         VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4291                         VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4292                 }
4293
4294                 // Leaving those out was a mistake, those were in the old code, and they
4295                 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4296                 // I couldn't reproduce it after adding those normalizations. --blub
4297                 VectorNormalize(r_refdef.view.frustum[0].normal);
4298                 VectorNormalize(r_refdef.view.frustum[1].normal);
4299                 VectorNormalize(r_refdef.view.frustum[2].normal);
4300                 VectorNormalize(r_refdef.view.frustum[3].normal);
4301
4302                 // make the corners absolute
4303                 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4304                 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4305                 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4306                 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4307
4308                 // one more normal
4309                 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4310
4311                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4312                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4313                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4314                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4315                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4316         }
4317         else
4318         {
4319                 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4320                 VectorScale(left,  1.0f, r_refdef.view.frustum[1].normal);
4321                 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4322                 VectorScale(up,  1.0f, r_refdef.view.frustum[3].normal);
4323                 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4324                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4325                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4326                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4327                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4328                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4329         }
4330         r_refdef.view.numfrustumplanes = 5;
4331
4332         if (r_refdef.view.useclipplane)
4333         {
4334                 r_refdef.view.numfrustumplanes = 6;
4335                 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4336         }
4337
4338         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4339                 PlaneClassify(r_refdef.view.frustum + i);
4340
4341         // LadyHavoc: note to all quake engine coders, Quake had a special case
4342         // for 90 degrees which assumed a square view (wrong), so I removed it,
4343         // Quake2 has it disabled as well.
4344
4345         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4346         //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4347         //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4348         //PlaneClassify(&frustum[0]);
4349
4350         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4351         //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4352         //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4353         //PlaneClassify(&frustum[1]);
4354
4355         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4356         //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4357         //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4358         //PlaneClassify(&frustum[2]);
4359
4360         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4361         //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4362         //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4363         //PlaneClassify(&frustum[3]);
4364
4365         // nearclip plane
4366         //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4367         //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4368         //PlaneClassify(&frustum[4]);
4369 }
4370
4371 static void R_View_UpdateWithScissor(const int *myscissor)
4372 {
4373         R_Main_ResizeViewCache();
4374         R_View_SetFrustum(myscissor);
4375         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4376         R_View_UpdateEntityVisible();
4377 }
4378
4379 static void R_View_Update(void)
4380 {
4381         R_Main_ResizeViewCache();
4382         R_View_SetFrustum(NULL);
4383         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4384         R_View_UpdateEntityVisible();
4385 }
4386
4387 float viewscalefpsadjusted = 1.0f;
4388
4389 static void R_GetScaledViewSize(int width, int height, int *outwidth, int *outheight)
4390 {
4391         float scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
4392         scale = bound(0.03125f, scale, 1.0f);
4393         *outwidth = (int)ceil(width * scale);
4394         *outheight = (int)ceil(height * scale);
4395 }
4396
4397 void R_SetupView(qboolean allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4398 {
4399         const float *customclipplane = NULL;
4400         float plane[4];
4401         int /*rtwidth,*/ rtheight;
4402         if (r_refdef.view.useclipplane && allowwaterclippingplane)
4403         {
4404                 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4405                 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4406                 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4407                 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4408                         dist = r_refdef.view.clipplane.dist;
4409                 plane[0] = r_refdef.view.clipplane.normal[0];
4410                 plane[1] = r_refdef.view.clipplane.normal[1];
4411                 plane[2] = r_refdef.view.clipplane.normal[2];
4412                 plane[3] = -dist;
4413                 customclipplane = plane;
4414         }
4415
4416         //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
4417         rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
4418
4419         if (!r_refdef.view.useperspective)
4420                 R_Viewport_InitOrtho3D(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane);
4421         else if (vid.stencil && r_useinfinitefarclip.integer)
4422                 R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane);
4423         else
4424                 R_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane);
4425         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4426         R_SetViewport(&r_refdef.view.viewport);
4427 }
4428
4429 void R_EntityMatrix(const matrix4x4_t *matrix)
4430 {
4431         if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4432         {
4433                 gl_modelmatrixchanged = false;
4434                 gl_modelmatrix = *matrix;
4435                 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4436                 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4437                 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4438                 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4439                 CHECKGLERROR
4440                 switch(vid.renderpath)
4441                 {
4442                 case RENDERPATH_GL32:
4443                 case RENDERPATH_GLES2:
4444                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4445                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4446                         break;
4447                 }
4448         }
4449 }
4450
4451 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4452 {
4453         r_viewport_t viewport;
4454
4455         CHECKGLERROR
4456
4457         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
4458         R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4459         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4460         R_SetViewport(&viewport);
4461         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4462         GL_Color(1, 1, 1, 1);
4463         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4464         GL_BlendFunc(GL_ONE, GL_ZERO);
4465         GL_ScissorTest(false);
4466         GL_DepthMask(false);
4467         GL_DepthRange(0, 1);
4468         GL_DepthTest(false);
4469         GL_DepthFunc(GL_LEQUAL);
4470         R_EntityMatrix(&identitymatrix);
4471         R_Mesh_ResetTextureState();
4472         GL_PolygonOffset(0, 0);
4473         switch(vid.renderpath)
4474         {
4475         case RENDERPATH_GL32:
4476         case RENDERPATH_GLES2:
4477                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4478                 break;
4479         }
4480         GL_CullFace(GL_NONE);
4481
4482         CHECKGLERROR
4483 }
4484
4485 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4486 {
4487         R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4488 }
4489
4490 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4491 {
4492         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4493         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4494         GL_Color(1, 1, 1, 1);
4495         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4496         GL_BlendFunc(GL_ONE, GL_ZERO);
4497         GL_ScissorTest(true);
4498         GL_DepthMask(true);
4499         GL_DepthRange(0, 1);
4500         GL_DepthTest(true);
4501         GL_DepthFunc(GL_LEQUAL);
4502         R_EntityMatrix(&identitymatrix);
4503         R_Mesh_ResetTextureState();
4504         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4505         switch(vid.renderpath)
4506         {
4507         case RENDERPATH_GL32:
4508         case RENDERPATH_GLES2:
4509                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4510                 break;
4511         }
4512         GL_CullFace(r_refdef.view.cullface_back);
4513 }
4514
4515 /*
4516 ================
4517 R_RenderView_UpdateViewVectors
4518 ================
4519 */
4520 void R_RenderView_UpdateViewVectors(void)
4521 {
4522         // break apart the view matrix into vectors for various purposes
4523         // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4524         // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4525         Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4526         VectorNegate(r_refdef.view.left, r_refdef.view.right);
4527         // make an inverted copy of the view matrix for tracking sprites
4528         Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4529 }
4530
4531 void R_RenderTarget_FreeUnused(qboolean force)
4532 {
4533         unsigned int i, j, end;
4534         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4535         for (i = 0; i < end; i++)
4536         {
4537                 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4538                 // free resources for rendertargets that have not been used for a while
4539                 // (note: this check is run after the frame render, so any targets used
4540                 // this frame will not be affected even at low framerates)
4541                 if (r && (realtime - r->lastusetime > 0.2 || force))
4542                 {
4543                         if (r->fbo)
4544                                 R_Mesh_DestroyFramebufferObject(r->fbo);
4545                         for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4546                                 if (r->colortexture[j])
4547                                         R_FreeTexture(r->colortexture[j]);
4548                         if (r->depthtexture)
4549                                 R_FreeTexture(r->depthtexture);
4550                         Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4551                 }
4552         }
4553 }
4554
4555 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4556 {
4557         float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4558         x1 = x * iw;
4559         x2 = (x + w) * iw;
4560         y1 = (th - y) * ih;
4561         y2 = (th - y - h) * ih;
4562         texcoord2f[0] = x1;
4563         texcoord2f[2] = x2;
4564         texcoord2f[4] = x2;
4565         texcoord2f[6] = x1;
4566         texcoord2f[1] = y1;
4567         texcoord2f[3] = y1;
4568         texcoord2f[5] = y2;
4569         texcoord2f[7] = y2;
4570 }
4571
4572 r_rendertarget_t *R_RenderTarget_Get(int texturewidth, int textureheight, textype_t depthtextype, qboolean depthisrenderbuffer, textype_t colortextype0, textype_t colortextype1, textype_t colortextype2, textype_t colortextype3)
4573 {
4574         unsigned int i, j, end;
4575         r_rendertarget_t *r = NULL;
4576         char vabuf[256];
4577         // first try to reuse an existing slot if possible
4578         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4579         for (i = 0; i < end; i++)
4580         {
4581                 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4582                 if (r && r->lastusetime != realtime && r->texturewidth == texturewidth && r->textureheight == textureheight && r->depthtextype == depthtextype && r->colortextype[0] == colortextype0 && r->colortextype[1] == colortextype1 && r->colortextype[2] == colortextype2 && r->colortextype[3] == colortextype3)
4583                         break;
4584         }
4585         if (i == end)
4586         {
4587                 // no unused exact match found, so we have to make one in the first unused slot
4588                 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4589                 r->texturewidth = texturewidth;
4590                 r->textureheight = textureheight;
4591                 r->colortextype[0] = colortextype0;
4592                 r->colortextype[1] = colortextype1;
4593                 r->colortextype[2] = colortextype2;
4594                 r->colortextype[3] = colortextype3;
4595                 r->depthtextype = depthtextype;
4596                 r->depthisrenderbuffer = depthisrenderbuffer;
4597                 for (j = 0; j < 4; j++)
4598                         if (r->colortextype[j])
4599                                 r->colortexture[j] = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "rendertarget%i_%i_type%i", i, j, (int)r->colortextype[j]), r->texturewidth, r->textureheight, NULL, r->colortextype[j], TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
4600                 if (r->depthtextype)
4601                 {
4602                         if (r->depthisrenderbuffer)
4603                                 r->depthtexture = R_LoadTextureRenderBuffer(r_main_texturepool, va(vabuf, sizeof(vabuf), "renderbuffer%i_depth_type%i", i, (int)r->depthtextype), r->texturewidth, r->textureheight, r->depthtextype);
4604                         else
4605                                 r->depthtexture = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "rendertarget%i_depth_type%i", i, j, (int)r->depthtextype), r->texturewidth, r->textureheight, NULL, r->depthtextype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
4606                 }
4607                 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4608         }
4609         r_refdef.stats[r_stat_rendertargets_used]++;
4610         r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4611         r->lastusetime = realtime;
4612         R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4613         return r;
4614 }
4615
4616 static void R_Water_StartFrame(void)
4617 {
4618         int waterwidth, waterheight;
4619
4620         if (vid.width > (int)vid.maxtexturesize_2d || vid.height > (int)vid.maxtexturesize_2d)
4621                 return;
4622
4623         // set waterwidth and waterheight to the water resolution that will be
4624         // used (often less than the screen resolution for faster rendering)
4625         waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width);
4626         waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height);
4627         R_GetScaledViewSize(waterwidth, waterheight, &waterwidth, &waterheight);
4628
4629         if (!r_water.integer || r_showsurfaces.integer)
4630                 waterwidth = waterheight = 0;
4631
4632         // set up variables that will be used in shader setup
4633         r_fb.water.waterwidth = waterwidth;
4634         r_fb.water.waterheight = waterheight;
4635         r_fb.water.texturewidth = waterwidth;
4636         r_fb.water.textureheight = waterheight;
4637         r_fb.water.camerawidth = waterwidth;
4638         r_fb.water.cameraheight = waterheight;
4639         r_fb.water.screenscale[0] = 0.5f;
4640         r_fb.water.screenscale[1] = 0.5f;
4641         r_fb.water.screencenter[0] = 0.5f;
4642         r_fb.water.screencenter[1] = 0.5f;
4643         r_fb.water.enabled = waterwidth != 0;
4644
4645         r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4646         r_fb.water.numwaterplanes = 0;
4647 }
4648
4649 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4650 {
4651         int planeindex, bestplaneindex, vertexindex;
4652         vec3_t mins, maxs, normal, center, v, n;
4653         vec_t planescore, bestplanescore;
4654         mplane_t plane;
4655         r_waterstate_waterplane_t *p;
4656         texture_t *t = R_GetCurrentTexture(surface->texture);
4657
4658         rsurface.texture = t;
4659         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4660         // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4661         if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4662                 return;
4663         // average the vertex normals, find the surface bounds (after deformvertexes)
4664         Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4665         Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4666         VectorCopy(n, normal);
4667         VectorCopy(v, mins);
4668         VectorCopy(v, maxs);
4669         for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4670         {
4671                 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4672                 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4673                 VectorAdd(normal, n, normal);
4674                 mins[0] = min(mins[0], v[0]);
4675                 mins[1] = min(mins[1], v[1]);
4676                 mins[2] = min(mins[2], v[2]);
4677                 maxs[0] = max(maxs[0], v[0]);
4678                 maxs[1] = max(maxs[1], v[1]);
4679                 maxs[2] = max(maxs[2], v[2]);
4680         }
4681         VectorNormalize(normal);
4682         VectorMAM(0.5f, mins, 0.5f, maxs, center);
4683
4684         VectorCopy(normal, plane.normal);
4685         VectorNormalize(plane.normal);
4686         plane.dist = DotProduct(center, plane.normal);
4687         PlaneClassify(&plane);
4688         if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4689         {
4690                 // skip backfaces (except if nocullface is set)
4691 //              if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4692 //                      return;
4693                 VectorNegate(plane.normal, plane.normal);
4694                 plane.dist *= -1;
4695                 PlaneClassify(&plane);
4696         }
4697
4698
4699         // find a matching plane if there is one
4700         bestplaneindex = -1;
4701         bestplanescore = 1048576.0f;
4702         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4703         {
4704                 if(p->camera_entity == t->camera_entity)
4705                 {
4706                         planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4707                         if (bestplaneindex < 0 || bestplanescore > planescore)
4708                         {
4709                                 bestplaneindex = planeindex;
4710                                 bestplanescore = planescore;
4711                         }
4712                 }
4713         }
4714         planeindex = bestplaneindex;
4715
4716         // if this surface does not fit any known plane rendered this frame, add one
4717         if (planeindex < 0 || bestplanescore > 0.001f)
4718         {
4719                 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4720                 {
4721                         // store the new plane
4722                         planeindex = r_fb.water.numwaterplanes++;
4723                         p = r_fb.water.waterplanes + planeindex;
4724                         p->plane = plane;
4725                         // clear materialflags and pvs
4726                         p->materialflags = 0;
4727                         p->pvsvalid = false;
4728                         p->camera_entity = t->camera_entity;
4729                         VectorCopy(mins, p->mins);
4730                         VectorCopy(maxs, p->maxs);
4731                 }
4732                 else
4733                 {
4734                         // We're totally screwed.
4735                         return;
4736                 }
4737         }
4738         else
4739         {
4740                 // merge mins/maxs when we're adding this surface to the plane
4741                 p = r_fb.water.waterplanes + planeindex;
4742                 p->mins[0] = min(p->mins[0], mins[0]);
4743                 p->mins[1] = min(p->mins[1], mins[1]);
4744                 p->mins[2] = min(p->mins[2], mins[2]);
4745                 p->maxs[0] = max(p->maxs[0], maxs[0]);
4746                 p->maxs[1] = max(p->maxs[1], maxs[1]);
4747                 p->maxs[2] = max(p->maxs[2], maxs[2]);
4748         }
4749         // merge this surface's materialflags into the waterplane
4750         p->materialflags |= t->currentmaterialflags;
4751         if(!(p->materialflags & MATERIALFLAG_CAMERA))
4752         {
4753                 // merge this surface's PVS into the waterplane
4754                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4755                  && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4756                 {
4757                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4758                         p->pvsvalid = true;
4759                 }
4760         }
4761 }
4762
4763 extern cvar_t r_drawparticles;
4764 extern cvar_t r_drawdecals;
4765
4766 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4767 {
4768         int myscissor[4];
4769         r_refdef_view_t originalview;
4770         r_refdef_view_t myview;
4771         int planeindex, qualityreduction = 0, old_r_dynamic = 0, old_r_shadows = 0, old_r_worldrtlight = 0, old_r_dlight = 0, old_r_particles = 0, old_r_decals = 0;
4772         r_waterstate_waterplane_t *p;
4773         vec3_t visorigin;
4774         r_rendertarget_t *rt;
4775
4776         originalview = r_refdef.view;
4777
4778         // lowquality hack, temporarily shut down some cvars and restore afterwards
4779         qualityreduction = r_water_lowquality.integer;
4780         if (qualityreduction > 0)
4781         {
4782                 if (qualityreduction >= 1)
4783                 {
4784                         old_r_shadows = r_shadows.integer;
4785                         old_r_worldrtlight = r_shadow_realtime_world.integer;
4786                         old_r_dlight = r_shadow_realtime_dlight.integer;
4787                         Cvar_SetValueQuick(&r_shadows, 0);
4788                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4789                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4790                 }
4791                 if (qualityreduction >= 2)
4792                 {
4793                         old_r_dynamic = r_dynamic.integer;
4794                         old_r_particles = r_drawparticles.integer;
4795                         old_r_decals = r_drawdecals.integer;
4796                         Cvar_SetValueQuick(&r_dynamic, 0);
4797                         Cvar_SetValueQuick(&r_drawparticles, 0);
4798                         Cvar_SetValueQuick(&r_drawdecals, 0);
4799                 }
4800         }
4801
4802         for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4803         {
4804                 p->rt_reflection = NULL;
4805                 p->rt_refraction = NULL;
4806                 p->rt_camera = NULL;
4807         }
4808
4809         // render views
4810         r_refdef.view = originalview;
4811         r_refdef.view.showdebug = false;
4812         r_refdef.view.width = r_fb.water.waterwidth;
4813         r_refdef.view.height = r_fb.water.waterheight;
4814         r_refdef.view.useclipplane = true;
4815         myview = r_refdef.view;
4816         r_fb.water.renderingscene = true;
4817         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4818         {
4819                 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4820                         continue;
4821
4822                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4823                 {
4824                         rt = R_RenderTarget_Get(r_fb.water.waterwidth, r_fb.water.waterheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, r_fb.rt_screen->colortextype[0], TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
4825                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4826                                 goto error;
4827                         r_refdef.view = myview;
4828                         Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4829                         Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4830                         if(r_water_scissormode.integer)
4831                         {
4832                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4833                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4834                                 {
4835                                         p->rt_reflection = NULL;
4836                                         p->rt_refraction = NULL;
4837                                         p->rt_camera = NULL;
4838                                         continue;
4839                                 }
4840                         }
4841
4842                         r_refdef.view.clipplane = p->plane;
4843                         // reflected view origin may be in solid, so don't cull with it
4844                         r_refdef.view.usevieworiginculling = false;
4845                         // reverse the cullface settings for this render
4846                         r_refdef.view.cullface_front = GL_FRONT;
4847                         r_refdef.view.cullface_back = GL_BACK;
4848                         // combined pvs (based on what can be seen from each surface center)
4849                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4850                         {
4851                                 r_refdef.view.usecustompvs = true;
4852                                 if (p->pvsvalid)
4853                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4854                                 else
4855                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4856                         }
4857
4858                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4859                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4860                         GL_ScissorTest(false);
4861                         R_ClearScreen(r_refdef.fogenabled);
4862                         GL_ScissorTest(true);
4863                         if(r_water_scissormode.integer & 2)
4864                                 R_View_UpdateWithScissor(myscissor);
4865                         else
4866                                 R_View_Update();
4867                         R_AnimCache_CacheVisibleEntities();
4868                         if(r_water_scissormode.integer & 1)
4869                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4870                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4871
4872                         r_fb.water.hideplayer = false;
4873                         p->rt_reflection = rt;
4874                 }
4875
4876                 // render the normal view scene and copy into texture
4877                 // (except that a clipping plane should be used to hide everything on one side of the water, and the viewer's weapon model should be omitted)
4878                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
4879                 {
4880                         rt = R_RenderTarget_Get(r_fb.water.waterwidth, r_fb.water.waterheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, r_fb.rt_screen->colortextype[0], TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
4881                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4882                                 goto error;
4883                         r_refdef.view = myview;
4884                         if(r_water_scissormode.integer)
4885                         {
4886                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4887                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4888                                 {
4889                                         p->rt_reflection = NULL;
4890                                         p->rt_refraction = NULL;
4891                                         p->rt_camera = NULL;
4892                                         continue;
4893                                 }
4894                         }
4895
4896                         // combined pvs (based on what can be seen from each surface center)
4897                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4898                         {
4899                                 r_refdef.view.usecustompvs = true;
4900                                 if (p->pvsvalid)
4901                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4902                                 else
4903                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4904                         }
4905
4906                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
4907
4908                         r_refdef.view.clipplane = p->plane;
4909                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
4910                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
4911
4912                         if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
4913                         {
4914                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
4915                                 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
4916                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
4917                                 R_RenderView_UpdateViewVectors();
4918                                 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
4919                                 {
4920                                         r_refdef.view.usecustompvs = true;
4921                                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, visorigin, 2, r_refdef.viewcache.world_pvsbits, (r_refdef.viewcache.world_numclusters+7)>>3, false);
4922                                 }
4923                         }
4924
4925                         PlaneClassify(&r_refdef.view.clipplane);
4926
4927                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4928                         GL_ScissorTest(false);
4929                         R_ClearScreen(r_refdef.fogenabled);
4930                         GL_ScissorTest(true);
4931                         if(r_water_scissormode.integer & 2)
4932                                 R_View_UpdateWithScissor(myscissor);
4933                         else
4934                                 R_View_Update();
4935                         R_AnimCache_CacheVisibleEntities();
4936                         if(r_water_scissormode.integer & 1)
4937                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4938                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4939
4940                         r_fb.water.hideplayer = false;
4941                         p->rt_refraction = rt;
4942                 }
4943                 else if (p->materialflags & MATERIALFLAG_CAMERA)
4944                 {
4945                         rt = R_RenderTarget_Get(r_fb.water.waterwidth, r_fb.water.waterheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, r_fb.rt_screen->colortextype[0], TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
4946                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4947                                 goto error;
4948                         r_refdef.view = myview;
4949
4950                         r_refdef.view.clipplane = p->plane;
4951                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
4952                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
4953
4954                         r_refdef.view.width = r_fb.water.camerawidth;
4955                         r_refdef.view.height = r_fb.water.cameraheight;
4956                         r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
4957                         r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
4958                         r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
4959                         r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
4960
4961                         if(p->camera_entity)
4962                         {
4963                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
4964                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
4965                         }
4966
4967                         // note: all of the view is used for displaying... so
4968                         // there is no use in scissoring
4969
4970                         // reverse the cullface settings for this render
4971                         r_refdef.view.cullface_front = GL_FRONT;
4972                         r_refdef.view.cullface_back = GL_BACK;
4973                         // also reverse the view matrix
4974                         Matrix4x4_ConcatScale3(&r_refdef.view.matrix, 1, 1, -1); // this serves to invert texcoords in the result, as the copied texture is mapped the wrong way round
4975                         R_RenderView_UpdateViewVectors();
4976                         if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
4977                         {
4978                                 r_refdef.view.usecustompvs = true;
4979                                 r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, visorigin, 2, r_refdef.viewcache.world_pvsbits, (r_refdef.viewcache.world_numclusters+7)>>3, false);
4980                         }
4981                         
4982                         // camera needs no clipplane
4983                         r_refdef.view.useclipplane = false;
4984                         // TODO: is the camera origin always valid?  if so we don't need to clear this
4985                         r_refdef.view.usevieworiginculling = false;
4986
4987                         PlaneClassify(&r_refdef.view.clipplane);
4988
4989                         r_fb.water.hideplayer = false;
4990
4991                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4992                         GL_ScissorTest(false);
4993                         R_ClearScreen(r_refdef.fogenabled);
4994                         GL_ScissorTest(true);
4995                         R_View_Update();
4996                         R_AnimCache_CacheVisibleEntities();
4997                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4998
4999                         r_fb.water.hideplayer = false;
5000                         p->rt_camera = rt;
5001                 }
5002
5003         }
5004         r_fb.water.renderingscene = false;
5005         r_refdef.view = originalview;
5006         R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5007         R_View_Update();
5008         R_AnimCache_CacheVisibleEntities();
5009         goto finish;
5010 error:
5011         r_refdef.view = originalview;
5012         r_fb.water.renderingscene = false;
5013         Cvar_SetValueQuick(&r_water, 0);
5014         Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed!  Turned off r_water.\n");
5015 finish:
5016         // lowquality hack, restore cvars
5017         if (qualityreduction > 0)
5018         {
5019                 if (qualityreduction >= 1)
5020                 {
5021                         Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5022                         Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5023                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5024                 }
5025                 if (qualityreduction >= 2)
5026                 {
5027                         Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5028                         Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5029                         Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5030                 }
5031         }
5032 }
5033
5034 static void R_Bloom_StartFrame(void)
5035 {
5036         int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
5037         int viewwidth, viewheight;
5038         textype_t textype = TEXTYPE_COLORBUFFER;
5039
5040         // clear the pointers to rendertargets from last frame as they're stale
5041         r_fb.rt_screen = NULL;
5042         r_fb.rt_bloom = NULL;
5043
5044         switch (vid.renderpath)
5045         {
5046         case RENDERPATH_GL32:
5047                 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5048                 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5049                 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5050                 break;
5051         case RENDERPATH_GLES2:
5052                 r_fb.usedepthtextures = false;
5053                 break;
5054         }
5055
5056         if (r_viewscale_fpsscaling.integer)
5057         {
5058                 double actualframetime;
5059                 double targetframetime;
5060                 double adjust;
5061                 actualframetime = r_refdef.lastdrawscreentime;
5062                 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5063                 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5064                 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5065                 if (r_viewscale_fpsscaling_stepsize.value > 0)
5066                         adjust = (int)(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5067                 viewscalefpsadjusted += adjust;
5068                 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5069         }
5070         else
5071                 viewscalefpsadjusted = 1.0f;
5072
5073         R_GetScaledViewSize(r_refdef.view.width, r_refdef.view.height, &viewwidth, &viewheight);
5074
5075         // set bloomwidth and bloomheight to the bloom resolution that will be
5076         // used (often less than the screen resolution for faster rendering)
5077         r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, vid.width);
5078         r_fb.bloomheight = r_fb.bloomwidth * vid.height / vid.width;
5079         r_fb.bloomheight = bound(1, r_fb.bloomheight, vid.height);
5080         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5081         r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5082
5083         // calculate desired texture sizes
5084         screentexturewidth = viewwidth;
5085         screentextureheight = viewheight;
5086         bloomtexturewidth = r_fb.bloomwidth;
5087         bloomtextureheight = r_fb.bloomheight;
5088
5089         if ((r_bloom.integer || (!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0))) && ((r_bloom_resolution.integer < 4 || r_bloom_blur.value < 1 || r_bloom_blur.value >= 512) || r_refdef.view.width > (int)vid.maxtexturesize_2d || r_refdef.view.height > (int)vid.maxtexturesize_2d))
5090         {
5091                 Cvar_SetValueQuick(&r_bloom, 0);
5092                 Cvar_SetValueQuick(&r_motionblur, 0);
5093                 Cvar_SetValueQuick(&r_damageblur, 0);
5094         }
5095
5096         // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5097         if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5098         {
5099                 if (r_fb.ghosttexture)
5100                         R_FreeTexture(r_fb.ghosttexture);
5101                 r_fb.ghosttexture = NULL;
5102
5103                 r_fb.screentexturewidth = screentexturewidth;
5104                 r_fb.screentextureheight = screentextureheight;
5105                 r_fb.textype = textype;
5106
5107                 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5108                 {
5109                         if (r_motionblur.value > 0 || r_damageblur.value > 0)
5110                                 r_fb.ghosttexture = R_LoadTexture2D(r_main_texturepool, "framebuffermotionblur", r_fb.screentexturewidth, r_fb.screentextureheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
5111                         r_fb.ghosttexture_valid = false;
5112                 }
5113         }
5114
5115         if (r_bloom.integer)
5116         {
5117                 // bloom texture is a different resolution
5118                 r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.width);
5119                 r_fb.bloomheight = r_fb.bloomwidth * r_refdef.view.height / r_refdef.view.width;
5120                 r_fb.bloomheight = bound(1, r_fb.bloomheight, r_refdef.view.height);
5121         }
5122         else
5123                 r_fb.bloomwidth = r_fb.bloomheight = 0;
5124
5125         r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5126
5127         r_refdef.view.clear = true;
5128 }
5129
5130 static void R_Bloom_MakeTexture(void)
5131 {
5132         int x, range, dir;
5133         float xoffset, yoffset, r, brighten;
5134         float colorscale = r_bloom_colorscale.value;
5135         r_viewport_t bloomviewport;
5136         r_rendertarget_t *prev, *cur;
5137         textype_t textype = r_fb.rt_screen->colortextype[0];
5138
5139         r_refdef.stats[r_stat_bloom]++;
5140
5141         R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5142
5143         // scale down screen texture to the bloom texture size
5144         CHECKGLERROR
5145         prev = r_fb.rt_screen;
5146         cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5147         R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5148         R_SetViewport(&bloomviewport);
5149         GL_CullFace(GL_NONE);
5150         GL_DepthTest(false);
5151         GL_BlendFunc(GL_ONE, GL_ZERO);
5152         GL_Color(colorscale, colorscale, colorscale, 1);
5153         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5154         // TODO: do boxfilter scale-down in shader?
5155         R_SetupShader_Generic(prev->colortexture[0], false, true, true);
5156         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5157         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5158         // we now have a properly scaled bloom image
5159
5160         // multiply bloom image by itself as many times as desired to darken it
5161         // TODO: if people actually use this it could be done more quickly in the previous shader pass
5162         for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5163         {
5164                 prev = cur;
5165                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5166                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5167                 x *= 2;
5168                 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5169                 if(x <= 2)
5170                         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0);
5171                 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5172                 GL_Color(1,1,1,1); // no fix factor supported here
5173                 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5174                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5175                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5176                 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5177         }
5178         CHECKGLERROR
5179
5180         range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5181         brighten = r_bloom_brighten.value;
5182         brighten = sqrt(brighten);
5183         if(range >= 1)
5184                 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5185
5186         for (dir = 0;dir < 2;dir++)
5187         {
5188                 prev = cur;
5189                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5190                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5191                 // blend on at multiple vertical offsets to achieve a vertical blur
5192                 // TODO: do offset blends using GLSL
5193                 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5194                 CHECKGLERROR
5195                 GL_BlendFunc(GL_ONE, GL_ZERO);
5196                 CHECKGLERROR
5197                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5198                 CHECKGLERROR
5199                 for (x = -range;x <= range;x++)
5200                 {
5201                         if (!dir){xoffset = 0;yoffset = x;}
5202                         else {xoffset = x;yoffset = 0;}
5203                         xoffset /= (float)prev->texturewidth;
5204                         yoffset /= (float)prev->textureheight;
5205                         // compute a texcoord array with the specified x and y offset
5206                         r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5207                         r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5208                         r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5209                         r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5210                         r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5211                         r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5212                         r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5213                         r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5214                         // this r value looks like a 'dot' particle, fading sharply to
5215                         // black at the edges
5216                         // (probably not realistic but looks good enough)
5217                         //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5218                         //r = brighten/(range*2+1);
5219                         r = brighten / (range * 2 + 1);
5220                         if(range >= 1)
5221                                 r *= (1 - x*x/(float)((range+1)*(range+1)));
5222                         if (r <= 0)
5223                                 continue;
5224                         CHECKGLERROR
5225                         GL_Color(r, r, r, 1);
5226                         CHECKGLERROR
5227                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5228                         CHECKGLERROR
5229                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5230                         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5231                         CHECKGLERROR
5232                         GL_BlendFunc(GL_ONE, GL_ONE);
5233                         CHECKGLERROR
5234                 }
5235         }
5236
5237         // now we have the bloom image, so keep track of it
5238         r_fb.rt_bloom = cur;
5239 }
5240
5241 static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5242 {
5243         dpuint64 permutation;
5244         float uservecs[4][4];
5245         rtexture_t *viewtexture;
5246         rtexture_t *bloomtexture;
5247
5248         R_EntityMatrix(&identitymatrix);
5249
5250         if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
5251         {
5252                 // declare variables
5253                 float blur_factor, blur_mouseaccel, blur_velocity;
5254                 static float blur_average; 
5255                 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5256
5257                 // set a goal for the factoring
5258                 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value) 
5259                         / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5260                 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value) 
5261                         / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5262                 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value) 
5263                         + (blur_mouseaccel * r_motionblur_mousefactor.value));
5264
5265                 // from the goal, pick an averaged value between goal and last value
5266                 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5267                 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5268
5269                 // enforce minimum amount of blur 
5270                 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5271
5272                 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5273
5274                 // calculate values into a standard alpha
5275                 cl.motionbluralpha = 1 - exp(-
5276                                 (
5277                                         (r_motionblur.value * blur_factor / 80)
5278                                         +
5279                                         (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5280                                 )
5281                                 /
5282                                 max(0.0001, cl.time - cl.oldtime) // fps independent
5283                                 );
5284
5285                 // randomization for the blur value to combat persistent ghosting
5286                 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5287                 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5288
5289                 // apply the blur
5290                 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5291                 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5292                 {
5293                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5294                         GL_Color(1, 1, 1, cl.motionbluralpha);
5295                         R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5296                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5297                         R_SetupShader_Generic(r_fb.ghosttexture, false, true, true);
5298                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5299                         r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5300                 }
5301
5302                 // updates old view angles for next pass
5303                 VectorCopy(cl.viewangles, blur_oldangles);
5304
5305                 // copy view into the ghost texture
5306                 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5307                 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5308                 r_fb.ghosttexture_valid = true;
5309         }
5310
5311         if (r_fb.bloomwidth)
5312         {
5313                 // make the bloom texture
5314                 R_Bloom_MakeTexture();
5315         }
5316
5317 #if _MSC_VER >= 1400
5318 #define sscanf sscanf_s
5319 #endif
5320         memset(uservecs, 0, sizeof(uservecs));
5321         if (r_glsl_postprocess_uservec1_enable.integer)
5322                 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5323         if (r_glsl_postprocess_uservec2_enable.integer)
5324                 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5325         if (r_glsl_postprocess_uservec3_enable.integer)
5326                 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5327         if (r_glsl_postprocess_uservec4_enable.integer)
5328                 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5329
5330         // render to the screen fbo
5331         R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5332         GL_Color(1, 1, 1, 1);
5333         GL_BlendFunc(GL_ONE, GL_ZERO);
5334
5335         viewtexture = r_fb.rt_screen->colortexture[0];
5336         bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5337
5338         if (r_rendertarget_debug.integer >= 0)
5339         {
5340                 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5341                 if (rt && rt->colortexture[0])
5342                 {
5343                         viewtexture = rt->colortexture[0];
5344                         bloomtexture = NULL;
5345                 }
5346         }
5347
5348         R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5349         switch(vid.renderpath)
5350         {
5351         case RENDERPATH_GL32:
5352         case RENDERPATH_GLES2:
5353                 permutation =
5354                         (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5355                         | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5356                         | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5357                         | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5358                         | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5359                 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5360                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First     , viewtexture);
5361                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second    , bloomtexture);
5362                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps       );
5363                 if (r_glsl_permutation->loc_ViewTintColor           >= 0) qglUniform4f(r_glsl_permutation->loc_ViewTintColor     , r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
5364                 if (r_glsl_permutation->loc_PixelSize               >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize         , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5365                 if (r_glsl_permutation->loc_UserVec1                >= 0) qglUniform4f(r_glsl_permutation->loc_UserVec1          , uservecs[0][0], uservecs[0][1], uservecs[0][2], uservecs[0][3]);
5366                 if (r_glsl_permutation->loc_UserVec2                >= 0) qglUniform4f(r_glsl_permutation->loc_UserVec2          , uservecs[1][0], uservecs[1][1], uservecs[1][2], uservecs[1][3]);
5367                 if (r_glsl_permutation->loc_UserVec3                >= 0) qglUniform4f(r_glsl_permutation->loc_UserVec3          , uservecs[2][0], uservecs[2][1], uservecs[2][2], uservecs[2][3]);
5368                 if (r_glsl_permutation->loc_UserVec4                >= 0) qglUniform4f(r_glsl_permutation->loc_UserVec4          , uservecs[3][0], uservecs[3][1], uservecs[3][2], uservecs[3][3]);
5369                 if (r_glsl_permutation->loc_Saturation              >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation        , r_glsl_saturation.value);
5370                 if (r_glsl_permutation->loc_PixelToScreenTexCoord   >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
5371                 if (r_glsl_permutation->loc_BloomColorSubtract      >= 0) qglUniform4f(r_glsl_permutation->loc_BloomColorSubtract   , r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, 0.0f);
5372                 break;
5373         }
5374         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5375         r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5376 }
5377
5378 matrix4x4_t r_waterscrollmatrix;
5379
5380 void R_UpdateFog(void)
5381 {
5382         // Nehahra fog
5383         if (gamemode == GAME_NEHAHRA)
5384         {
5385                 if (gl_fogenable.integer)
5386                 {
5387                         r_refdef.oldgl_fogenable = true;
5388                         r_refdef.fog_density = gl_fogdensity.value;
5389                         r_refdef.fog_red = gl_fogred.value;
5390                         r_refdef.fog_green = gl_foggreen.value;
5391                         r_refdef.fog_blue = gl_fogblue.value;
5392                         r_refdef.fog_alpha = 1;
5393                         r_refdef.fog_start = 0;
5394                         r_refdef.fog_end = gl_skyclip.value;
5395                         r_refdef.fog_height = 1<<30;
5396                         r_refdef.fog_fadedepth = 128;
5397                 }
5398                 else if (r_refdef.oldgl_fogenable)
5399                 {
5400                         r_refdef.oldgl_fogenable = false;
5401                         r_refdef.fog_density = 0;
5402                         r_refdef.fog_red = 0;
5403                         r_refdef.fog_green = 0;
5404                         r_refdef.fog_blue = 0;
5405                         r_refdef.fog_alpha = 0;
5406                         r_refdef.fog_start = 0;
5407                         r_refdef.fog_end = 0;
5408                         r_refdef.fog_height = 1<<30;
5409                         r_refdef.fog_fadedepth = 128;
5410                 }
5411         }
5412
5413         // fog parms
5414         r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5415         r_refdef.fog_start = max(0, r_refdef.fog_start);
5416         r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5417
5418         if (r_refdef.fog_density && r_drawfog.integer)
5419         {
5420                 r_refdef.fogenabled = true;
5421                 // this is the point where the fog reaches 0.9986 alpha, which we
5422                 // consider a good enough cutoff point for the texture
5423                 // (0.9986 * 256 == 255.6)
5424                 if (r_fog_exp2.integer)
5425                         r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5426                 else
5427                         r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5428                 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5429                 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5430                 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5431                 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5432                         R_BuildFogHeightTexture();
5433                 // fog color was already set
5434                 // update the fog texture
5435                 if (r_refdef.fogmasktable_start != r_refdef.fog_start || r_refdef.fogmasktable_alpha != r_refdef.fog_alpha || r_refdef.fogmasktable_density != r_refdef.fog_density || r_refdef.fogmasktable_range != r_refdef.fogrange)
5436                         R_BuildFogTexture();
5437                 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5438                 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5439         }
5440         else
5441                 r_refdef.fogenabled = false;
5442
5443         // fog color
5444         if (r_refdef.fog_density)
5445         {
5446                 r_refdef.fogcolor[0] = r_refdef.fog_red;
5447                 r_refdef.fogcolor[1] = r_refdef.fog_green;
5448                 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5449
5450                 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5451                 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5452                 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5453                 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5454
5455                 {
5456                         vec3_t fogvec;
5457                         VectorCopy(r_refdef.fogcolor, fogvec);
5458                         //   color.rgb *= ContrastBoost * SceneBrightness;
5459                         VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5460                         r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5461                         r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5462                         r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5463                 }
5464         }
5465 }
5466
5467 void R_UpdateVariables(void)
5468 {
5469         R_Textures_Frame();
5470
5471         r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5472
5473         r_refdef.farclip = r_farclip_base.value;
5474         if (r_refdef.scene.worldmodel)
5475                 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5476         r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5477
5478         if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5479                 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5480         r_refdef.polygonfactor = 0;
5481         r_refdef.polygonoffset = 0;
5482
5483         r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5484         r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5485         r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5486         r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5487         r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5488         if (r_refdef.scene.worldmodel)
5489         {
5490                 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5491         }
5492         if (r_showsurfaces.integer)
5493         {
5494                 r_refdef.scene.rtworld = false;
5495                 r_refdef.scene.rtworldshadows = false;
5496                 r_refdef.scene.rtdlight = false;
5497                 r_refdef.scene.rtdlightshadows = false;
5498                 r_refdef.scene.lightmapintensity = 0;
5499         }
5500
5501         r_gpuskeletal = false;
5502         switch(vid.renderpath)
5503         {
5504         case RENDERPATH_GL32:
5505                 r_gpuskeletal = r_glsl_skeletal.integer && !r_showsurfaces.integer;
5506         case RENDERPATH_GLES2:
5507                 if(!vid_gammatables_trivial)
5508                 {
5509                         if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5510                         {
5511                                 // build GLSL gamma texture
5512 #define RAMPWIDTH 256
5513                                 unsigned short ramp[RAMPWIDTH * 3];
5514                                 unsigned char rampbgr[RAMPWIDTH][4];
5515                                 int i;
5516
5517                                 r_texture_gammaramps_serial = vid_gammatables_serial;
5518
5519                                 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5520                                 for(i = 0; i < RAMPWIDTH; ++i)
5521                                 {
5522                                         rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5523                                         rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5524                                         rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5525                                         rampbgr[i][3] = 0;
5526                                 }
5527                                 if (r_texture_gammaramps)
5528                                 {
5529                                         R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1);
5530                                 }
5531                                 else
5532                                 {
5533                                         r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5534                                 }
5535                         }
5536                 }
5537                 else
5538                 {
5539                         // remove GLSL gamma texture
5540                 }
5541                 break;
5542         }
5543 }
5544
5545 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5546 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5547 /*
5548 ================
5549 R_SelectScene
5550 ================
5551 */
5552 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5553         if( scenetype != r_currentscenetype ) {
5554                 // store the old scenetype
5555                 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5556                 r_currentscenetype = scenetype;
5557                 // move in the new scene
5558                 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5559         }
5560 }
5561
5562 /*
5563 ================
5564 R_GetScenePointer
5565 ================
5566 */
5567 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5568 {
5569         // of course, we could also add a qboolean that provides a lock state and a ReleaseScenePointer function..
5570         if( scenetype == r_currentscenetype ) {
5571                 return &r_refdef.scene;
5572         } else {
5573                 return &r_scenes_store[ scenetype ];
5574         }
5575 }
5576
5577 static int R_SortEntities_Compare(const void *ap, const void *bp)
5578 {
5579         const entity_render_t *a = *(const entity_render_t **)ap;
5580         const entity_render_t *b = *(const entity_render_t **)bp;
5581
5582         // 1. compare model
5583         if(a->model < b->model)
5584                 return -1;
5585         if(a->model > b->model)
5586                 return +1;
5587
5588         // 2. compare skin
5589         // TODO possibly calculate the REAL skinnum here first using
5590         // skinscenes?
5591         if(a->skinnum < b->skinnum)
5592                 return -1;
5593         if(a->skinnum > b->skinnum)
5594                 return +1;
5595
5596         // everything we compared is equal
5597         return 0;
5598 }
5599 static void R_SortEntities(void)
5600 {
5601         // below or equal 2 ents, sorting never gains anything
5602         if(r_refdef.scene.numentities <= 2)
5603                 return;
5604         // sort
5605         qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5606 }
5607
5608 /*
5609 ================
5610 R_RenderView
5611 ================
5612 */
5613 extern cvar_t r_shadow_bouncegrid;
5614 extern cvar_t v_isometric;
5615 extern void V_MakeViewIsometric(void);
5616 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5617 {
5618         matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5619         int viewfbo = 0;
5620         rtexture_t *viewdepthtexture = NULL;
5621         rtexture_t *viewcolortexture = NULL;
5622         int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5623
5624         // finish any 2D rendering that was queued
5625         DrawQ_Finish();
5626
5627         if (r_timereport_active)
5628                 R_TimeReport("start");
5629         r_textureframe++; // used only by R_GetCurrentTexture
5630         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5631
5632         if(R_CompileShader_CheckStaticParms())
5633                 R_GLSL_Restart_f(&cmd_client);
5634
5635         if (!r_drawentities.integer)
5636                 r_refdef.scene.numentities = 0;
5637         else if (r_sortentities.integer)
5638                 R_SortEntities();
5639
5640         R_AnimCache_ClearCache();
5641
5642         /* adjust for stereo display */
5643         if(R_Stereo_Active())
5644         {
5645                 Matrix4x4_CreateFromQuakeEntity(&offsetmatrix, 0, r_stereo_separation.value * (0.5f - r_stereo_side), 0, 0, r_stereo_angle.value * (0.5f - r_stereo_side), 0, 1);
5646                 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5647         }
5648
5649         if (r_refdef.view.isoverlay)
5650         {
5651                 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5652                 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5653                 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5654                 R_TimeReport("depthclear");
5655
5656                 r_refdef.view.showdebug = false;
5657
5658                 r_fb.water.enabled = false;
5659                 r_fb.water.numwaterplanes = 0;
5660
5661                 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5662
5663                 r_refdef.view.matrix = originalmatrix;
5664
5665                 CHECKGLERROR
5666                 return;
5667         }
5668
5669         if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5670         {
5671                 r_refdef.view.matrix = originalmatrix;
5672                 return;
5673         }
5674
5675         r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5676         if (v_isometric.integer && r_refdef.view.ismain)
5677                 V_MakeViewIsometric();
5678
5679         r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5680
5681         if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5682                 // in sRGB fallback, behave similar to true sRGB: convert this
5683                 // value from linear to sRGB
5684                 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5685
5686         R_RenderView_UpdateViewVectors();
5687
5688         R_Shadow_UpdateWorldLightSelection();
5689
5690         // this will set up r_fb.rt_screen
5691         R_Bloom_StartFrame();
5692
5693         // apply bloom brightness offset
5694         if(r_fb.rt_bloom)
5695                 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5696
5697         // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5698         if (r_fb.rt_screen)
5699         {
5700                 viewfbo = r_fb.rt_screen->fbo;
5701                 viewdepthtexture = r_fb.rt_screen->depthtexture;
5702                 viewcolortexture = r_fb.rt_screen->colortexture[0];
5703                 viewx = 0;
5704                 viewy = 0;
5705                 viewwidth = width;
5706                 viewheight = height;
5707         }
5708
5709         R_Water_StartFrame();
5710
5711         CHECKGLERROR
5712         if (r_timereport_active)
5713                 R_TimeReport("viewsetup");
5714
5715         R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5716
5717         // clear the whole fbo every frame - otherwise the driver will consider
5718         // it to be an inter-frame texture and stall in multi-gpu configurations
5719         if (r_fb.rt_screen)
5720                 GL_ScissorTest(false);
5721         R_ClearScreen(r_refdef.fogenabled);
5722         if (r_timereport_active)
5723                 R_TimeReport("viewclear");
5724
5725         r_refdef.view.clear = true;
5726
5727         r_refdef.view.showdebug = true;
5728
5729         R_View_Update();
5730         if (r_timereport_active)
5731                 R_TimeReport("visibility");
5732
5733         R_AnimCache_CacheVisibleEntities();
5734         if (r_timereport_active)
5735                 R_TimeReport("animcache");
5736
5737         R_Shadow_UpdateBounceGridTexture();
5738         // R_Shadow_UpdateBounceGridTexture called R_TimeReport a few times internally, so we don't need to do that here.
5739
5740         r_fb.water.numwaterplanes = 0;
5741         if (r_fb.water.enabled)
5742                 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5743
5744         // for the actual view render we use scissoring a fair amount, so scissor
5745         // test needs to be on
5746         if (r_fb.rt_screen)
5747                 GL_ScissorTest(true);
5748         GL_Scissor(viewx, viewy, viewwidth, viewheight);
5749         R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5750         r_fb.water.numwaterplanes = 0;
5751
5752         // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5753         GL_ScissorTest(false);
5754
5755         R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
5756         if (r_timereport_active)
5757                 R_TimeReport("blendview");
5758
5759         r_refdef.view.matrix = originalmatrix;
5760
5761         CHECKGLERROR
5762
5763         // go back to 2d rendering
5764         DrawQ_Start();
5765 }
5766
5767 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5768 {
5769         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5770         {
5771                 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5772                 if (r_timereport_active)
5773                         R_TimeReport("waterworld");
5774         }
5775
5776         // don't let sound skip if going slow
5777         if (r_refdef.scene.extraupdate)
5778                 S_ExtraUpdate ();
5779
5780         R_DrawModelsAddWaterPlanes();
5781         if (r_timereport_active)
5782                 R_TimeReport("watermodels");
5783
5784         if (r_fb.water.numwaterplanes)
5785         {
5786                 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5787                 if (r_timereport_active)
5788                         R_TimeReport("waterscenes");
5789         }
5790 }
5791
5792 extern cvar_t cl_locs_show;
5793 static void R_DrawLocs(void);
5794 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5795 static void R_DrawModelDecals(void);
5796 extern qboolean r_shadow_usingdeferredprepass;
5797 extern int r_shadow_shadowmapatlas_modelshadows_size;
5798 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5799 {
5800         qboolean shadowmapping = false;
5801
5802         if (r_timereport_active)
5803                 R_TimeReport("beginscene");
5804
5805         r_refdef.stats[r_stat_renders]++;
5806
5807         R_UpdateFog();
5808
5809         // don't let sound skip if going slow
5810         if (r_refdef.scene.extraupdate)
5811                 S_ExtraUpdate ();
5812
5813         R_MeshQueue_BeginScene();
5814
5815         R_SkyStartFrame();
5816
5817         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);
5818
5819         if (r_timereport_active)
5820                 R_TimeReport("skystartframe");
5821
5822         if (cl.csqc_vidvars.drawworld)
5823         {
5824                 // don't let sound skip if going slow
5825                 if (r_refdef.scene.extraupdate)
5826                         S_ExtraUpdate ();
5827
5828                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5829                 {
5830                         r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5831                         if (r_timereport_active)
5832                                 R_TimeReport("worldsky");
5833                 }
5834
5835                 if (R_DrawBrushModelsSky() && r_timereport_active)
5836                         R_TimeReport("bmodelsky");
5837
5838                 if (skyrendermasked && skyrenderlater)
5839                 {
5840                         // we have to force off the water clipping plane while rendering sky
5841                         R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5842                         R_Sky();
5843                         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5844                         if (r_timereport_active)
5845                                 R_TimeReport("sky");
5846                 }
5847         }
5848
5849         // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5850         r_shadow_viewfbo = viewfbo;
5851         r_shadow_viewdepthtexture = viewdepthtexture;
5852         r_shadow_viewcolortexture = viewcolortexture;
5853         r_shadow_viewx = viewx;
5854         r_shadow_viewy = viewy;
5855         r_shadow_viewwidth = viewwidth;
5856         r_shadow_viewheight = viewheight;
5857
5858         R_Shadow_PrepareModelShadows();
5859         R_Shadow_PrepareLights();
5860         if (r_timereport_active)
5861                 R_TimeReport("preparelights");
5862
5863         // render all the shadowmaps that will be used for this view
5864         shadowmapping = R_Shadow_ShadowMappingEnabled();
5865         if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
5866         {
5867                 R_Shadow_DrawShadowMaps();
5868                 if (r_timereport_active)
5869                         R_TimeReport("shadowmaps");
5870         }
5871
5872         // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
5873         if (r_shadow_usingdeferredprepass)
5874                 R_Shadow_DrawPrepass();
5875
5876         // now we begin the forward pass of the view render
5877         if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
5878         {
5879                 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
5880                 if (r_timereport_active)
5881                         R_TimeReport("worlddepth");
5882         }
5883         if (r_depthfirst.integer >= 2)
5884         {
5885                 R_DrawModelsDepth();
5886                 if (r_timereport_active)
5887                         R_TimeReport("modeldepth");
5888         }
5889
5890         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
5891         {
5892                 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
5893                 if (r_timereport_active)
5894                         R_TimeReport("world");
5895         }
5896
5897         // don't let sound skip if going slow
5898         if (r_refdef.scene.extraupdate)
5899                 S_ExtraUpdate ();
5900
5901         R_DrawModels();
5902         if (r_timereport_active)
5903                 R_TimeReport("models");
5904
5905         // don't let sound skip if going slow
5906         if (r_refdef.scene.extraupdate)
5907                 S_ExtraUpdate ();
5908
5909         if (!r_shadow_usingdeferredprepass)
5910         {
5911                 R_Shadow_DrawLights();
5912                 if (r_timereport_active)
5913                         R_TimeReport("rtlights");
5914         }
5915
5916         // don't let sound skip if going slow
5917         if (r_refdef.scene.extraupdate)
5918                 S_ExtraUpdate ();
5919
5920         if (cl.csqc_vidvars.drawworld)
5921         {
5922                 R_DrawModelDecals();
5923                 if (r_timereport_active)
5924                         R_TimeReport("modeldecals");
5925
5926                 R_DrawParticles();
5927                 if (r_timereport_active)
5928                         R_TimeReport("particles");
5929
5930                 R_DrawExplosions();
5931                 if (r_timereport_active)
5932                         R_TimeReport("explosions");
5933         }
5934
5935         if (r_refdef.view.showdebug)
5936         {
5937                 if (cl_locs_show.integer)
5938                 {
5939                         R_DrawLocs();
5940                         if (r_timereport_active)
5941                                 R_TimeReport("showlocs");
5942                 }
5943
5944                 if (r_drawportals.integer)
5945                 {
5946                         R_DrawPortals();
5947                         if (r_timereport_active)
5948                                 R_TimeReport("portals");
5949                 }
5950
5951                 if (r_showbboxes_client.value > 0)
5952                 {
5953                         R_DrawEntityBBoxes(CLVM_prog);
5954                         if (r_timereport_active)
5955                                 R_TimeReport("clbboxes");
5956                 }
5957                 if (r_showbboxes.value > 0)
5958                 {
5959                         R_DrawEntityBBoxes(SVVM_prog);
5960                         if (r_timereport_active)
5961                                 R_TimeReport("svbboxes");
5962                 }
5963         }
5964
5965         if (r_transparent.integer)
5966         {
5967                 R_MeshQueue_RenderTransparent();
5968                 if (r_timereport_active)
5969                         R_TimeReport("drawtrans");
5970         }
5971
5972         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))
5973         {
5974                 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
5975                 if (r_timereport_active)
5976                         R_TimeReport("worlddebug");
5977                 R_DrawModelsDebug();
5978                 if (r_timereport_active)
5979                         R_TimeReport("modeldebug");
5980         }
5981
5982         if (cl.csqc_vidvars.drawworld)
5983         {
5984                 R_Shadow_DrawCoronas();
5985                 if (r_timereport_active)
5986                         R_TimeReport("coronas");
5987         }
5988
5989         // don't let sound skip if going slow
5990         if (r_refdef.scene.extraupdate)
5991                 S_ExtraUpdate ();
5992 }
5993
5994 static const unsigned short bboxelements[36] =
5995 {
5996         5, 1, 3, 5, 3, 7,
5997         6, 2, 0, 6, 0, 4,
5998         7, 3, 2, 7, 2, 6,
5999         4, 0, 1, 4, 1, 5,
6000         4, 5, 7, 4, 7, 6,
6001         1, 0, 2, 1, 2, 3,
6002 };
6003
6004 #define BBOXEDGES 13
6005 static const float bboxedges[BBOXEDGES][6] = 
6006 {
6007         // whole box
6008         { 0, 0, 0, 1, 1, 1 },
6009         // bottom edges
6010         { 0, 0, 0, 0, 1, 0 },
6011         { 0, 0, 0, 1, 0, 0 },
6012         { 0, 1, 0, 1, 1, 0 },
6013         { 1, 0, 0, 1, 1, 0 },
6014         // top edges
6015         { 0, 0, 1, 0, 1, 1 },
6016         { 0, 0, 1, 1, 0, 1 },
6017         { 0, 1, 1, 1, 1, 1 },
6018         { 1, 0, 1, 1, 1, 1 },
6019         // vertical edges
6020         { 0, 0, 0, 0, 0, 1 },
6021         { 1, 0, 0, 1, 0, 1 },
6022         { 0, 1, 0, 0, 1, 1 },
6023         { 1, 1, 0, 1, 1, 1 },
6024 };
6025
6026 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6027 {
6028         int numvertices = BBOXEDGES * 8;
6029         float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6030         int numtriangles = BBOXEDGES * 12;
6031         unsigned short elements[BBOXEDGES * 36];
6032         int i, edge;
6033         float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6034
6035         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6036
6037         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6038         GL_DepthMask(false);
6039         GL_DepthRange(0, 1);
6040         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6041
6042         for (edge = 0; edge < BBOXEDGES; edge++)
6043         {
6044                 for (i = 0; i < 3; i++)
6045                 {
6046                         edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6047                         edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6048                 }
6049                 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6050                 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6051                 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6052                 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6053                 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6054                 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6055                 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6056                 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6057                 for (i = 0; i < 36; i++)
6058                         elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6059         }
6060         R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6061         if (r_refdef.fogenabled)
6062         {
6063                 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6064                 {
6065                         f1 = RSurf_FogVertex(v);
6066                         f2 = 1 - f1;
6067                         c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6068                         c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6069                         c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6070                 }
6071         }
6072         R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6073         R_Mesh_ResetTextureState();
6074         R_SetupShader_Generic_NoTexture(false, false);
6075         R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6076 }
6077
6078 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6079 {
6080         // hacky overloading of the parameters
6081         prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6082         int i;
6083         float color[4];
6084         prvm_edict_t *edict;
6085
6086         GL_CullFace(GL_NONE);
6087         R_SetupShader_Generic_NoTexture(false, false);
6088
6089         for (i = 0;i < numsurfaces;i++)
6090         {
6091                 edict = PRVM_EDICT_NUM(surfacelist[i]);
6092                 switch ((int)PRVM_serveredictfloat(edict, solid))
6093                 {
6094                         case SOLID_NOT:      Vector4Set(color, 1, 1, 1, 0.05);break;
6095                         case SOLID_TRIGGER:  Vector4Set(color, 1, 0, 1, 0.10);break;
6096                         case SOLID_BBOX:     Vector4Set(color, 0, 1, 0, 0.10);break;
6097                         case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6098                         case SOLID_BSP:      Vector4Set(color, 0, 0, 1, 0.05);break;
6099                         case SOLID_CORPSE:   Vector4Set(color, 1, 0.5, 0, 0.05);break;
6100                         default:             Vector4Set(color, 0, 0, 0, 0.50);break;
6101                 }
6102                 if (prog == CLVM_prog)
6103                         color[3] *= r_showbboxes_client.value;
6104                 else
6105                         color[3] *= r_showbboxes.value;
6106                 color[3] = bound(0, color[3], 1);
6107                 GL_DepthTest(!r_showdisabledepthtest.integer);
6108                 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6109         }
6110 }
6111
6112 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6113 {
6114         int i;
6115         prvm_edict_t *edict;
6116         vec3_t center;
6117
6118         if (prog == NULL)
6119                 return;
6120
6121         for (i = 0; i < prog->num_edicts; i++)
6122         {
6123                 edict = PRVM_EDICT_NUM(i);
6124                 if (edict->priv.server->free)
6125                         continue;
6126                 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6127                 if (PRVM_serveredictedict(edict, tag_entity) != 0)
6128                         continue;
6129                 if (PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6130                         continue;
6131                 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6132                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6133         }
6134 }
6135
6136 static const int nomodelelement3i[24] =
6137 {
6138         5, 2, 0,
6139         5, 1, 2,
6140         5, 0, 3,
6141         5, 3, 1,
6142         0, 2, 4,
6143         2, 1, 4,
6144         3, 0, 4,
6145         1, 3, 4
6146 };
6147
6148 static const unsigned short nomodelelement3s[24] =
6149 {
6150         5, 2, 0,
6151         5, 1, 2,
6152         5, 0, 3,
6153         5, 3, 1,
6154         0, 2, 4,
6155         2, 1, 4,
6156         3, 0, 4,
6157         1, 3, 4
6158 };
6159
6160 static const float nomodelvertex3f[6*3] =
6161 {
6162         -16,   0,   0,
6163          16,   0,   0,
6164           0, -16,   0,
6165           0,  16,   0,
6166           0,   0, -16,
6167           0,   0,  16
6168 };
6169
6170 static const float nomodelcolor4f[6*4] =
6171 {
6172         0.0f, 0.0f, 0.5f, 1.0f,
6173         0.0f, 0.0f, 0.5f, 1.0f,
6174         0.0f, 0.5f, 0.0f, 1.0f,
6175         0.0f, 0.5f, 0.0f, 1.0f,
6176         0.5f, 0.0f, 0.0f, 1.0f,
6177         0.5f, 0.0f, 0.0f, 1.0f
6178 };
6179
6180 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6181 {
6182         int i;
6183         float f1, f2, *c;
6184         float color4f[6*4];
6185
6186         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);
6187
6188         // this is only called once per entity so numsurfaces is always 1, and
6189         // surfacelist is always {0}, so this code does not handle batches
6190
6191         if (rsurface.ent_flags & RENDER_ADDITIVE)
6192         {
6193                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6194                 GL_DepthMask(false);
6195         }
6196         else if (ent->alpha < 1)
6197         {
6198                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6199                 GL_DepthMask(false);
6200         }
6201         else
6202         {
6203                 GL_BlendFunc(GL_ONE, GL_ZERO);
6204                 GL_DepthMask(true);
6205         }
6206         GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6207         GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6208         GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6209         GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6210         memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6211         for (i = 0, c = color4f;i < 6;i++, c += 4)
6212         {
6213                 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6214                 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6215                 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6216                 c[3] *= ent->alpha;
6217         }
6218         if (r_refdef.fogenabled)
6219         {
6220                 for (i = 0, c = color4f;i < 6;i++, c += 4)
6221                 {
6222                         f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6223                         f2 = 1 - f1;
6224                         c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6225                         c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6226                         c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6227                 }
6228         }
6229 //      R_Mesh_ResetTextureState();
6230         R_SetupShader_Generic_NoTexture(false, false);
6231         R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6232         R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6233 }
6234
6235 void R_DrawNoModel(entity_render_t *ent)
6236 {
6237         vec3_t org;
6238         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6239         if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6240                 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6241         else
6242                 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6243 }
6244
6245 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6246 {
6247         vec3_t right1, right2, diff, normal;
6248
6249         VectorSubtract (org2, org1, normal);
6250
6251         // calculate 'right' vector for start
6252         VectorSubtract (r_refdef.view.origin, org1, diff);
6253         CrossProduct (normal, diff, right1);
6254         VectorNormalize (right1);
6255
6256         // calculate 'right' vector for end
6257         VectorSubtract (r_refdef.view.origin, org2, diff);
6258         CrossProduct (normal, diff, right2);
6259         VectorNormalize (right2);
6260
6261         vert[ 0] = org1[0] + width * right1[0];
6262         vert[ 1] = org1[1] + width * right1[1];
6263         vert[ 2] = org1[2] + width * right1[2];
6264         vert[ 3] = org1[0] - width * right1[0];
6265         vert[ 4] = org1[1] - width * right1[1];
6266         vert[ 5] = org1[2] - width * right1[2];
6267         vert[ 6] = org2[0] - width * right2[0];
6268         vert[ 7] = org2[1] - width * right2[1];
6269         vert[ 8] = org2[2] - width * right2[2];
6270         vert[ 9] = org2[0] + width * right2[0];
6271         vert[10] = org2[1] + width * right2[1];
6272         vert[11] = org2[2] + width * right2[2];
6273 }
6274
6275 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)
6276 {
6277         vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6278         vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6279         vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6280         vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6281         vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6282         vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6283         vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6284         vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6285         vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6286         vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6287         vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6288         vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6289 }
6290
6291 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6292 {
6293         int i;
6294         float *vertex3f;
6295         float v[3];
6296         VectorSet(v, x, y, z);
6297         for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6298                 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6299                         break;
6300         if (i == mesh->numvertices)
6301         {
6302                 if (mesh->numvertices < mesh->maxvertices)
6303                 {
6304                         VectorCopy(v, vertex3f);
6305                         mesh->numvertices++;
6306                 }
6307                 return mesh->numvertices;
6308         }
6309         else
6310                 return i;
6311 }
6312
6313 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6314 {
6315         int i;
6316         int *e, element[3];
6317         element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6318         element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6319         e = mesh->element3i + mesh->numtriangles * 3;
6320         for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6321         {
6322                 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6323                 if (mesh->numtriangles < mesh->maxtriangles)
6324                 {
6325                         *e++ = element[0];
6326                         *e++ = element[1];
6327                         *e++ = element[2];
6328                         mesh->numtriangles++;
6329                 }
6330                 element[1] = element[2];
6331         }
6332 }
6333
6334 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6335 {
6336         int i;
6337         int *e, element[3];
6338         element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6339         element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6340         e = mesh->element3i + mesh->numtriangles * 3;
6341         for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6342         {
6343                 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6344                 if (mesh->numtriangles < mesh->maxtriangles)
6345                 {
6346                         *e++ = element[0];
6347                         *e++ = element[1];
6348                         *e++ = element[2];
6349                         mesh->numtriangles++;
6350                 }
6351                 element[1] = element[2];
6352         }
6353 }
6354
6355 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6356 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6357 {
6358         int planenum, planenum2;
6359         int w;
6360         int tempnumpoints;
6361         mplane_t *plane, *plane2;
6362         double maxdist;
6363         double temppoints[2][256*3];
6364         // figure out how large a bounding box we need to properly compute this brush
6365         maxdist = 0;
6366         for (w = 0;w < numplanes;w++)
6367                 maxdist = max(maxdist, fabs(planes[w].dist));
6368         // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6369         maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6370         for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6371         {
6372                 w = 0;
6373                 tempnumpoints = 4;
6374                 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6375                 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6376                 {
6377                         if (planenum2 == planenum)
6378                                 continue;
6379                         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);
6380                         w = !w;
6381                 }
6382                 if (tempnumpoints < 3)
6383                         continue;
6384                 // generate elements forming a triangle fan for this polygon
6385                 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6386         }
6387 }
6388
6389 static qboolean R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6390 {
6391         if(parms[0] == 0 && parms[1] == 0)
6392                 return false;
6393         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6394                 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6395                         return false;
6396         return true;
6397 }
6398
6399 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6400 {
6401         double index, f;
6402         index = parms[2] + rsurface.shadertime * parms[3];
6403         index -= floor(index);
6404         switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6405         {
6406         default:
6407         case Q3WAVEFUNC_NONE:
6408         case Q3WAVEFUNC_NOISE:
6409         case Q3WAVEFUNC_COUNT:
6410                 f = 0;
6411                 break;
6412         case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6413         case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6414         case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6415         case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6416         case Q3WAVEFUNC_TRIANGLE:
6417                 index *= 4;
6418                 f = index - floor(index);
6419                 if (index < 1)
6420                 {
6421                         // f = f;
6422                 }
6423                 else if (index < 2)
6424                         f = 1 - f;
6425                 else if (index < 3)
6426                         f = -f;
6427                 else
6428                         f = -(1 - f);
6429                 break;
6430         }
6431         f = parms[0] + parms[1] * f;
6432         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6433                 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6434         return (float) f;
6435 }
6436
6437 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6438 {
6439         int w, h, idx;
6440         float shadertime;
6441         float f;
6442         float offsetd[2];
6443         float tcmat[12];
6444         matrix4x4_t matrix, temp;
6445         // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6446         // it's better to have one huge fixup every 9 hours than gradual
6447         // degradation over time which looks consistently bad after many hours.
6448         //
6449         // tcmod scroll in particular suffers from this degradation which can't be
6450         // effectively worked around even with floor() tricks because we don't
6451         // know if tcmod scroll is the last tcmod being applied, and for clampmap
6452         // a workaround involving floor() would be incorrect anyway...
6453         shadertime = rsurface.shadertime;
6454         if (shadertime >= 32768.0f)
6455                 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6456         switch(tcmod->tcmod)
6457         {
6458                 case Q3TCMOD_COUNT:
6459                 case Q3TCMOD_NONE:
6460                         if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6461                                 matrix = r_waterscrollmatrix;
6462                         else
6463                                 matrix = identitymatrix;
6464                         break;
6465                 case Q3TCMOD_ENTITYTRANSLATE:
6466                         // this is used in Q3 to allow the gamecode to control texcoord
6467                         // scrolling on the entity, which is not supported in darkplaces yet.
6468                         Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6469                         break;
6470                 case Q3TCMOD_ROTATE:
6471                         Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6472                         Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6473                         Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6474                         break;
6475                 case Q3TCMOD_SCALE:
6476                         Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6477                         break;
6478                 case Q3TCMOD_SCROLL:
6479                         // this particular tcmod is a "bug for bug" compatible one with regards to
6480                         // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6481                         // specifically did the wrapping and so we must mimic that...
6482                         offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6483                         offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6484                         Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6485                         break;
6486                 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6487                         w = (int) tcmod->parms[0];
6488                         h = (int) tcmod->parms[1];
6489                         f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6490                         f = f - floor(f);
6491                         idx = (int) floor(f * w * h);
6492                         Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6493                         break;
6494                 case Q3TCMOD_STRETCH:
6495                         f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6496                         Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6497                         break;
6498                 case Q3TCMOD_TRANSFORM:
6499                         VectorSet(tcmat +  0, tcmod->parms[0], tcmod->parms[1], 0);
6500                         VectorSet(tcmat +  3, tcmod->parms[2], tcmod->parms[3], 0);
6501                         VectorSet(tcmat +  6, 0                   , 0                , 1);
6502                         VectorSet(tcmat +  9, tcmod->parms[4], tcmod->parms[5], 0);
6503                         Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6504                         break;
6505                 case Q3TCMOD_TURBULENT:
6506                         // this is handled in the RSurf_PrepareVertices function
6507                         matrix = identitymatrix;
6508                         break;
6509         }
6510         temp = *texmatrix;
6511         Matrix4x4_Concat(texmatrix, &matrix, &temp);
6512 }
6513
6514 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6515 {
6516         int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6517         char name[MAX_QPATH];
6518         skinframe_t *skinframe;
6519         unsigned char pixels[296*194];
6520         strlcpy(cache->name, skinname, sizeof(cache->name));
6521         dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6522         if (developer_loading.integer)
6523                 Con_Printf("loading %s\n", name);
6524         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6525         if (!skinframe || !skinframe->base)
6526         {
6527                 unsigned char *f;
6528                 fs_offset_t filesize;
6529                 skinframe = NULL;
6530                 f = FS_LoadFile(name, tempmempool, true, &filesize);
6531                 if (f)
6532                 {
6533                         if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6534                                 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6535                         Mem_Free(f);
6536                 }
6537         }
6538         cache->skinframe = skinframe;
6539 }
6540
6541 texture_t *R_GetCurrentTexture(texture_t *t)
6542 {
6543         int i, q;
6544         const entity_render_t *ent = rsurface.entity;
6545         dp_model_t *model = ent->model; // when calling this, ent must not be NULL
6546         q3shaderinfo_layer_tcmod_t *tcmod;
6547         float specularscale = 0.0f;
6548
6549         if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6550                 return t->currentframe;
6551         t->update_lastrenderframe = r_textureframe;
6552         t->update_lastrenderentity = (void *)ent;
6553
6554         if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6555                 t->camera_entity = ent->entitynumber;
6556         else
6557                 t->camera_entity = 0;
6558
6559         // switch to an alternate material if this is a q1bsp animated material
6560         {
6561                 texture_t *texture = t;
6562                 int s = rsurface.ent_skinnum;
6563                 if ((unsigned int)s >= (unsigned int)model->numskins)
6564                         s = 0;
6565                 if (model->skinscenes)
6566                 {
6567                         if (model->skinscenes[s].framecount > 1)
6568                                 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6569                         else
6570                                 s = model->skinscenes[s].firstframe;
6571                 }
6572                 if (s > 0)
6573                         t = t + s * model->num_surfaces;
6574                 if (t->animated)
6575                 {
6576                         // use an alternate animation if the entity's frame is not 0,
6577                         // and only if the texture has an alternate animation
6578                         if (t->animated == 2) // q2bsp
6579                                 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6580                         else if (rsurface.ent_alttextures && t->anim_total[1])
6581                                 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6582                         else
6583                                 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6584                 }
6585                 texture->currentframe = t;
6586         }
6587
6588         // update currentskinframe to be a qw skin or animation frame
6589         if (rsurface.ent_qwskin >= 0)
6590         {
6591                 i = rsurface.ent_qwskin;
6592                 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6593                 {
6594                         r_qwskincache_size = cl.maxclients;
6595                         if (r_qwskincache)
6596                                 Mem_Free(r_qwskincache);
6597                         r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6598                 }
6599                 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6600                         R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6601                 t->currentskinframe = r_qwskincache[i].skinframe;
6602                 if (t->materialshaderpass && t->currentskinframe == NULL)
6603                         t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6604         }
6605         else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6606                 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6607         if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6608                 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6609
6610         t->currentmaterialflags = t->basematerialflags;
6611         t->currentalpha = rsurface.entity->alpha * t->basealpha;
6612         if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_water.integer || r_novis.integer || r_trippy.integer))
6613                 t->currentalpha *= r_wateralpha.value;
6614         if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6615                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6616         if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6617                 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6618
6619         // decide on which type of lighting to use for this surface
6620         if (rsurface.entity->render_modellight_forced)
6621                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6622         if (rsurface.entity->render_rtlight_disabled)
6623                 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6624         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6625         {
6626                 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6627                 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NORTLIGHT;
6628                 for (q = 0; q < 3; q++)
6629                 {
6630                         t->render_glowmod[q] = rsurface.entity->glowmod[q];
6631                         t->render_modellight_lightdir[q] = q == 2;
6632                         t->render_modellight_ambient[q] = 1;
6633                         t->render_modellight_diffuse[q] = 0;
6634                         t->render_modellight_specular[q] = 0;
6635                         t->render_lightmap_ambient[q] = 0;
6636                         t->render_lightmap_diffuse[q] = 0;
6637                         t->render_lightmap_specular[q] = 0;
6638                         t->render_rtlight_diffuse[q] = 0;
6639                         t->render_rtlight_specular[q] = 0;
6640                 }
6641         }
6642         else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6643         {
6644                 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6645                 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT;
6646                 for (q = 0; q < 3; q++)
6647                 {
6648                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6649                         t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6650                         t->render_modellight_lightdir[q] = q == 2;
6651                         t->render_modellight_diffuse[q] = 0;
6652                         t->render_modellight_specular[q] = 0;
6653                         t->render_lightmap_ambient[q] = 0;
6654                         t->render_lightmap_diffuse[q] = 0;
6655                         t->render_lightmap_specular[q] = 0;
6656                         t->render_rtlight_diffuse[q] = 0;
6657                         t->render_rtlight_specular[q] = 0;
6658                 }
6659         }
6660         else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6661         {
6662                 // ambient + single direction light (modellight)
6663                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6664                 for (q = 0; q < 3; q++)
6665                 {
6666                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6667                         t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6668                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6669                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6670                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6671                         t->render_lightmap_ambient[q] = 0;
6672                         t->render_lightmap_diffuse[q] = 0;
6673                         t->render_lightmap_specular[q] = 0;
6674                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6675                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6676                 }
6677         }
6678         else
6679         {
6680                 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6681                 for (q = 0; q < 3; q++)
6682                 {
6683                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6684                         t->render_modellight_lightdir[q] = q == 2;
6685                         t->render_modellight_ambient[q] = 0;
6686                         t->render_modellight_diffuse[q] = 0;
6687                         t->render_modellight_specular[q] = 0;
6688                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6689                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6690                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6691                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6692                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6693                 }
6694         }
6695
6696         if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6697         {
6698                 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6699                 // attribute, we punt it to the lightmap path and hope for the best,
6700                 // but lighting doesn't work.
6701                 //
6702                 // FIXME: this is fine for effects but CSQC polygons should be subject
6703                 // to lighting.
6704                 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6705                 for (q = 0; q < 3; q++)
6706                 {
6707                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6708                         t->render_modellight_lightdir[q] = q == 2;
6709                         t->render_modellight_ambient[q] = 0;
6710                         t->render_modellight_diffuse[q] = 0;
6711                         t->render_modellight_specular[q] = 0;
6712                         t->render_lightmap_ambient[q] = 0;
6713                         t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6714                         t->render_lightmap_specular[q] = 0;
6715                         t->render_rtlight_diffuse[q] = 0;
6716                         t->render_rtlight_specular[q] = 0;
6717                 }
6718         }
6719
6720         for (q = 0; q < 3; q++)
6721         {
6722                 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6723                 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6724         }
6725
6726         if (rsurface.ent_flags & RENDER_ADDITIVE)
6727                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6728         else if (t->currentalpha < 1)
6729                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6730         // LadyHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6731         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6732                 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6733         if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6734                 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6735         if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6736                 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6737         if (t->backgroundshaderpass)
6738                 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6739         if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6740         {
6741                 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6742                         t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6743         }
6744         else
6745                 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6746         if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6747         {
6748                 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6749                 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6750         }
6751         if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6752                 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6753
6754         // there is no tcmod
6755         if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6756         {
6757                 t->currenttexmatrix = r_waterscrollmatrix;
6758                 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6759         }
6760         else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6761         {
6762                 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6763                 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6764         }
6765
6766         if (t->materialshaderpass)
6767                 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6768                         R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6769
6770         t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6771         if (t->currentskinframe->qpixels)
6772                 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6773         t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6774         if (!t->basetexture)
6775                 t->basetexture = r_texture_notexture;
6776         t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6777         t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6778         t->nmaptexture = t->currentskinframe->nmap;
6779         if (!t->nmaptexture)
6780                 t->nmaptexture = r_texture_blanknormalmap;
6781         t->glosstexture = r_texture_black;
6782         t->glowtexture = t->currentskinframe->glow;
6783         t->fogtexture = t->currentskinframe->fog;
6784         t->reflectmasktexture = t->currentskinframe->reflect;
6785         if (t->backgroundshaderpass)
6786         {
6787                 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6788                         R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6789                 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6790                 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6791                 t->backgroundglosstexture = r_texture_black;
6792                 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6793                 if (!t->backgroundnmaptexture)
6794                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6795                 // make sure that if glow is going to be used, both textures are not NULL
6796                 if (!t->backgroundglowtexture && t->glowtexture)
6797                         t->backgroundglowtexture = r_texture_black;
6798                 if (!t->glowtexture && t->backgroundglowtexture)
6799                         t->glowtexture = r_texture_black;
6800         }
6801         else
6802         {
6803                 t->backgroundbasetexture = r_texture_white;
6804                 t->backgroundnmaptexture = r_texture_blanknormalmap;
6805                 t->backgroundglosstexture = r_texture_black;
6806                 t->backgroundglowtexture = NULL;
6807         }
6808         t->specularpower = r_shadow_glossexponent.value;
6809         // TODO: store reference values for these in the texture?
6810         if (r_shadow_gloss.integer > 0)
6811         {
6812                 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
6813                 {
6814                         if (r_shadow_glossintensity.value > 0)
6815                         {
6816                                 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
6817                                 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
6818                                 specularscale = r_shadow_glossintensity.value;
6819                         }
6820                 }
6821                 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
6822                 {
6823                         t->glosstexture = r_texture_white;
6824                         t->backgroundglosstexture = r_texture_white;
6825                         specularscale = r_shadow_gloss2intensity.value;
6826                         t->specularpower = r_shadow_gloss2exponent.value;
6827                 }
6828         }
6829         specularscale *= t->specularscalemod;
6830         t->specularpower *= t->specularpowermod;
6831
6832         // lightmaps mode looks bad with dlights using actual texturing, so turn
6833         // off the colormap and glossmap, but leave the normalmap on as it still
6834         // accurately represents the shading involved
6835         if (gl_lightmaps.integer)
6836         {
6837                 t->basetexture = r_texture_grey128;
6838                 t->pantstexture = r_texture_black;
6839                 t->shirttexture = r_texture_black;
6840                 if (gl_lightmaps.integer < 2)
6841                         t->nmaptexture = r_texture_blanknormalmap;
6842                 t->glosstexture = r_texture_black;
6843                 t->glowtexture = NULL;
6844                 t->fogtexture = NULL;
6845                 t->reflectmasktexture = NULL;
6846                 t->backgroundbasetexture = NULL;
6847                 if (gl_lightmaps.integer < 2)
6848                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6849                 t->backgroundglosstexture = r_texture_black;
6850                 t->backgroundglowtexture = NULL;
6851                 specularscale = 0;
6852                 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
6853         }
6854
6855         if (specularscale != 1.0f)
6856         {
6857                 for (q = 0; q < 3; q++)
6858                 {
6859                         t->render_modellight_specular[q] *= specularscale;
6860                         t->render_lightmap_specular[q] *= specularscale;
6861                         t->render_rtlight_specular[q] *= specularscale;
6862                 }
6863         }
6864
6865         t->currentblendfunc[0] = GL_ONE;
6866         t->currentblendfunc[1] = GL_ZERO;
6867         if (t->currentmaterialflags & MATERIALFLAG_ADD)
6868         {
6869                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6870                 t->currentblendfunc[1] = GL_ONE;
6871         }
6872         else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
6873         {
6874                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6875                 t->currentblendfunc[1] = GL_ONE_MINUS_SRC_ALPHA;
6876         }
6877         else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6878         {
6879                 t->currentblendfunc[0] = t->customblendfunc[0];
6880                 t->currentblendfunc[1] = t->customblendfunc[1];
6881         }
6882
6883         return t;
6884 }
6885
6886 rsurfacestate_t rsurface;
6887
6888 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
6889 {
6890         dp_model_t *model = ent->model;
6891         //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
6892         //      return;
6893         rsurface.entity = (entity_render_t *)ent;
6894         rsurface.skeleton = ent->skeleton;
6895         memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
6896         rsurface.ent_skinnum = ent->skinnum;
6897         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;
6898         rsurface.ent_flags = ent->flags;
6899         if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
6900                 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
6901         rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
6902         rsurface.matrix = ent->matrix;
6903         rsurface.inversematrix = ent->inversematrix;
6904         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
6905         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
6906         R_EntityMatrix(&rsurface.matrix);
6907         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
6908         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
6909         rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
6910         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
6911         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
6912         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
6913         memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
6914         rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
6915         rsurface.basepolygonfactor = r_refdef.polygonfactor;
6916         rsurface.basepolygonoffset = r_refdef.polygonoffset;
6917         if (ent->model->brush.submodel && !prepass)
6918         {
6919                 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
6920                 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
6921         }
6922         // if the animcache code decided it should use the shader path, skip the deform step
6923         rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
6924         rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
6925         rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
6926         rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
6927         rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
6928         if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
6929         {
6930                 if (ent->animcache_vertex3f)
6931                 {
6932                         r_refdef.stats[r_stat_batch_entitycache_count]++;
6933                         r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
6934                         r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
6935                         r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
6936                         rsurface.modelvertex3f = ent->animcache_vertex3f;
6937                         rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
6938                         rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
6939                         rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
6940                         rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
6941                         rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
6942                         rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
6943                         rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
6944                         rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
6945                         rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
6946                         rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
6947                         rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
6948                 }
6949                 else if (wanttangents)
6950                 {
6951                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
6952                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
6953                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
6954                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
6955                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6956                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6957                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6958                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6959                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
6960                         rsurface.modelvertex3f_vertexbuffer = NULL;
6961                         rsurface.modelvertex3f_bufferoffset = 0;
6962                         rsurface.modelvertex3f_vertexbuffer = 0;
6963                         rsurface.modelvertex3f_bufferoffset = 0;
6964                         rsurface.modelsvector3f_vertexbuffer = 0;
6965                         rsurface.modelsvector3f_bufferoffset = 0;
6966                         rsurface.modeltvector3f_vertexbuffer = 0;
6967                         rsurface.modeltvector3f_bufferoffset = 0;
6968                         rsurface.modelnormal3f_vertexbuffer = 0;
6969                         rsurface.modelnormal3f_bufferoffset = 0;
6970                 }
6971                 else if (wantnormals)
6972                 {
6973                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
6974                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
6975                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
6976                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
6977                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6978                         rsurface.modelsvector3f = NULL;
6979                         rsurface.modeltvector3f = NULL;
6980                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6981                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
6982                         rsurface.modelvertex3f_vertexbuffer = NULL;
6983                         rsurface.modelvertex3f_bufferoffset = 0;
6984                         rsurface.modelvertex3f_vertexbuffer = 0;
6985                         rsurface.modelvertex3f_bufferoffset = 0;
6986                         rsurface.modelsvector3f_vertexbuffer = 0;
6987                         rsurface.modelsvector3f_bufferoffset = 0;
6988                         rsurface.modeltvector3f_vertexbuffer = 0;
6989                         rsurface.modeltvector3f_bufferoffset = 0;
6990                         rsurface.modelnormal3f_vertexbuffer = 0;
6991                         rsurface.modelnormal3f_bufferoffset = 0;
6992                 }
6993                 else
6994                 {
6995                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
6996                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
6997                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
6998                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
6999                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7000                         rsurface.modelsvector3f = NULL;
7001                         rsurface.modeltvector3f = NULL;
7002                         rsurface.modelnormal3f = NULL;
7003                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7004                         rsurface.modelvertex3f_vertexbuffer = NULL;
7005                         rsurface.modelvertex3f_bufferoffset = 0;
7006                         rsurface.modelvertex3f_vertexbuffer = 0;
7007                         rsurface.modelvertex3f_bufferoffset = 0;
7008                         rsurface.modelsvector3f_vertexbuffer = 0;
7009                         rsurface.modelsvector3f_bufferoffset = 0;
7010                         rsurface.modeltvector3f_vertexbuffer = 0;
7011                         rsurface.modeltvector3f_bufferoffset = 0;
7012                         rsurface.modelnormal3f_vertexbuffer = 0;
7013                         rsurface.modelnormal3f_bufferoffset = 0;
7014                 }
7015                 rsurface.modelgeneratedvertex = true;
7016         }
7017         else
7018         {
7019                 if (rsurface.entityskeletaltransform3x4)
7020                 {
7021                         r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7022                         r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7023                         r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7024                         r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7025                 }
7026                 else
7027                 {
7028                         r_refdef.stats[r_stat_batch_entitystatic_count]++;
7029                         r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7030                         r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7031                         r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7032                 }
7033                 rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
7034                 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.data_vertex3f_vertexbuffer;
7035                 rsurface.modelvertex3f_bufferoffset = model->surfmesh.data_vertex3f_bufferoffset;
7036                 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7037                 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.data_svector3f_vertexbuffer;
7038                 rsurface.modelsvector3f_bufferoffset = model->surfmesh.data_svector3f_bufferoffset;
7039                 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7040                 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.data_tvector3f_vertexbuffer;
7041                 rsurface.modeltvector3f_bufferoffset = model->surfmesh.data_tvector3f_bufferoffset;
7042                 rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
7043                 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.data_normal3f_vertexbuffer;
7044                 rsurface.modelnormal3f_bufferoffset = model->surfmesh.data_normal3f_bufferoffset;
7045                 rsurface.modelgeneratedvertex = false;
7046         }
7047         rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
7048         rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.data_lightmapcolor4f_vertexbuffer;
7049         rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.data_lightmapcolor4f_bufferoffset;
7050         rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
7051         rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.data_texcoordtexture2f_vertexbuffer;
7052         rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.data_texcoordtexture2f_bufferoffset;
7053         rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
7054         rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.data_texcoordlightmap2f_vertexbuffer;
7055         rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.data_texcoordlightmap2f_bufferoffset;
7056         rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7057         rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.data_skeletalindex4ub_vertexbuffer;
7058         rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.data_skeletalindex4ub_bufferoffset;
7059         rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7060         rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.data_skeletalweight4ub_vertexbuffer;
7061         rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.data_skeletalweight4ub_bufferoffset;
7062         rsurface.modelelement3i = model->surfmesh.data_element3i;
7063         rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7064         rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7065         rsurface.modelelement3s = model->surfmesh.data_element3s;
7066         rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7067         rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7068         rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7069         rsurface.modelnumvertices = model->surfmesh.num_vertices;
7070         rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7071         rsurface.modelsurfaces = model->data_surfaces;
7072         rsurface.batchgeneratedvertex = false;
7073         rsurface.batchfirstvertex = 0;
7074         rsurface.batchnumvertices = 0;
7075         rsurface.batchfirsttriangle = 0;
7076         rsurface.batchnumtriangles = 0;
7077         rsurface.batchvertex3f  = NULL;
7078         rsurface.batchvertex3f_vertexbuffer = NULL;
7079         rsurface.batchvertex3f_bufferoffset = 0;
7080         rsurface.batchsvector3f = NULL;
7081         rsurface.batchsvector3f_vertexbuffer = NULL;
7082         rsurface.batchsvector3f_bufferoffset = 0;
7083         rsurface.batchtvector3f = NULL;
7084         rsurface.batchtvector3f_vertexbuffer = NULL;
7085         rsurface.batchtvector3f_bufferoffset = 0;
7086         rsurface.batchnormal3f  = NULL;
7087         rsurface.batchnormal3f_vertexbuffer = NULL;
7088         rsurface.batchnormal3f_bufferoffset = 0;
7089         rsurface.batchlightmapcolor4f = NULL;
7090         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7091         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7092         rsurface.batchtexcoordtexture2f = NULL;
7093         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7094         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7095         rsurface.batchtexcoordlightmap2f = NULL;
7096         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7097         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7098         rsurface.batchskeletalindex4ub = NULL;
7099         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7100         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7101         rsurface.batchskeletalweight4ub = NULL;
7102         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7103         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7104         rsurface.batchelement3i = NULL;
7105         rsurface.batchelement3i_indexbuffer = NULL;
7106         rsurface.batchelement3i_bufferoffset = 0;
7107         rsurface.batchelement3s = NULL;
7108         rsurface.batchelement3s_indexbuffer = NULL;
7109         rsurface.batchelement3s_bufferoffset = 0;
7110         rsurface.forcecurrenttextureupdate = false;
7111 }
7112
7113 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)
7114 {
7115         rsurface.entity = r_refdef.scene.worldentity;
7116         if (r != 1.0f || g != 1.0f || b != 1.0f || a != 1.0f) {
7117                 // HACK to provide a valid entity with modded colors to R_GetCurrentTexture.
7118                 // A better approach could be making this copy only once per frame.
7119                 static entity_render_t custom_entity;
7120                 int q;
7121                 custom_entity = *rsurface.entity;
7122                 for (q = 0; q < 3; ++q) {
7123                         float colormod = q == 0 ? r : q == 1 ? g : b;
7124                         custom_entity.render_fullbright[q] *= colormod;
7125                         custom_entity.render_modellight_ambient[q] *= colormod;
7126                         custom_entity.render_modellight_diffuse[q] *= colormod;
7127                         custom_entity.render_lightmap_ambient[q] *= colormod;
7128                         custom_entity.render_lightmap_diffuse[q] *= colormod;
7129                         custom_entity.render_rtlight_diffuse[q] *= colormod;
7130                 }
7131                 custom_entity.alpha *= a;
7132                 rsurface.entity = &custom_entity;
7133         }
7134         rsurface.skeleton = NULL;
7135         rsurface.ent_skinnum = 0;
7136         rsurface.ent_qwskin = -1;
7137         rsurface.ent_flags = entflags;
7138         rsurface.shadertime = r_refdef.scene.time - shadertime;
7139         rsurface.modelnumvertices = numvertices;
7140         rsurface.modelnumtriangles = numtriangles;
7141         rsurface.matrix = *matrix;
7142         rsurface.inversematrix = *inversematrix;
7143         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7144         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7145         R_EntityMatrix(&rsurface.matrix);
7146         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7147         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7148         rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7149         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7150         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7151         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7152         memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7153         rsurface.frameblend[0].lerp = 1;
7154         rsurface.ent_alttextures = false;
7155         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7156         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7157         rsurface.entityskeletaltransform3x4 = NULL;
7158         rsurface.entityskeletaltransform3x4buffer = NULL;
7159         rsurface.entityskeletaltransform3x4offset = 0;
7160         rsurface.entityskeletaltransform3x4size = 0;
7161         rsurface.entityskeletalnumtransforms = 0;
7162         r_refdef.stats[r_stat_batch_entitycustom_count]++;
7163         r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7164         r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7165         r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7166         if (wanttangents)
7167         {
7168                 rsurface.modelvertex3f = (float *)vertex3f;
7169                 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7170                 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7171                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7172         }
7173         else if (wantnormals)
7174         {
7175                 rsurface.modelvertex3f = (float *)vertex3f;
7176                 rsurface.modelsvector3f = NULL;
7177                 rsurface.modeltvector3f = NULL;
7178                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7179         }
7180         else
7181         {
7182                 rsurface.modelvertex3f = (float *)vertex3f;
7183                 rsurface.modelsvector3f = NULL;
7184                 rsurface.modeltvector3f = NULL;
7185                 rsurface.modelnormal3f = NULL;
7186         }
7187         rsurface.modelvertex3f_vertexbuffer = 0;
7188         rsurface.modelvertex3f_bufferoffset = 0;
7189         rsurface.modelsvector3f_vertexbuffer = 0;
7190         rsurface.modelsvector3f_bufferoffset = 0;
7191         rsurface.modeltvector3f_vertexbuffer = 0;
7192         rsurface.modeltvector3f_bufferoffset = 0;
7193         rsurface.modelnormal3f_vertexbuffer = 0;
7194         rsurface.modelnormal3f_bufferoffset = 0;
7195         rsurface.modelgeneratedvertex = true;
7196         rsurface.modellightmapcolor4f  = (float *)color4f;
7197         rsurface.modellightmapcolor4f_vertexbuffer = 0;
7198         rsurface.modellightmapcolor4f_bufferoffset = 0;
7199         rsurface.modeltexcoordtexture2f  = (float *)texcoord2f;
7200         rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7201         rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7202         rsurface.modeltexcoordlightmap2f  = NULL;
7203         rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7204         rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7205         rsurface.modelskeletalindex4ub = NULL;
7206         rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7207         rsurface.modelskeletalindex4ub_bufferoffset = 0;
7208         rsurface.modelskeletalweight4ub = NULL;
7209         rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7210         rsurface.modelskeletalweight4ub_bufferoffset = 0;
7211         rsurface.modelelement3i = (int *)element3i;
7212         rsurface.modelelement3i_indexbuffer = NULL;
7213         rsurface.modelelement3i_bufferoffset = 0;
7214         rsurface.modelelement3s = (unsigned short *)element3s;
7215         rsurface.modelelement3s_indexbuffer = NULL;
7216         rsurface.modelelement3s_bufferoffset = 0;
7217         rsurface.modellightmapoffsets = NULL;
7218         rsurface.modelsurfaces = NULL;
7219         rsurface.batchgeneratedvertex = false;
7220         rsurface.batchfirstvertex = 0;
7221         rsurface.batchnumvertices = 0;
7222         rsurface.batchfirsttriangle = 0;
7223         rsurface.batchnumtriangles = 0;
7224         rsurface.batchvertex3f  = NULL;
7225         rsurface.batchvertex3f_vertexbuffer = NULL;
7226         rsurface.batchvertex3f_bufferoffset = 0;
7227         rsurface.batchsvector3f = NULL;
7228         rsurface.batchsvector3f_vertexbuffer = NULL;
7229         rsurface.batchsvector3f_bufferoffset = 0;
7230         rsurface.batchtvector3f = NULL;
7231         rsurface.batchtvector3f_vertexbuffer = NULL;
7232         rsurface.batchtvector3f_bufferoffset = 0;
7233         rsurface.batchnormal3f  = NULL;
7234         rsurface.batchnormal3f_vertexbuffer = NULL;
7235         rsurface.batchnormal3f_bufferoffset = 0;
7236         rsurface.batchlightmapcolor4f = NULL;
7237         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7238         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7239         rsurface.batchtexcoordtexture2f = NULL;
7240         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7241         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7242         rsurface.batchtexcoordlightmap2f = NULL;
7243         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7244         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7245         rsurface.batchskeletalindex4ub = NULL;
7246         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7247         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7248         rsurface.batchskeletalweight4ub = NULL;
7249         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7250         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7251         rsurface.batchelement3i = NULL;
7252         rsurface.batchelement3i_indexbuffer = NULL;
7253         rsurface.batchelement3i_bufferoffset = 0;
7254         rsurface.batchelement3s = NULL;
7255         rsurface.batchelement3s_indexbuffer = NULL;
7256         rsurface.batchelement3s_bufferoffset = 0;
7257         rsurface.forcecurrenttextureupdate = true;
7258
7259         if (rsurface.modelnumvertices && rsurface.modelelement3i)
7260         {
7261                 if ((wantnormals || wanttangents) && !normal3f)
7262                 {
7263                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7264                         Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7265                 }
7266                 if (wanttangents && !svector3f)
7267                 {
7268                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7269                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7270                         Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7271                 }
7272         }
7273 }
7274
7275 float RSurf_FogPoint(const float *v)
7276 {
7277         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7278         float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7279         float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7280         float FogHeightFade = r_refdef.fogheightfade;
7281         float fogfrac;
7282         unsigned int fogmasktableindex;
7283         if (r_refdef.fogplaneviewabove)
7284                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7285         else
7286                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7287         fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7288         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7289 }
7290
7291 float RSurf_FogVertex(const float *v)
7292 {
7293         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7294         float FogPlaneViewDist = rsurface.fogplaneviewdist;
7295         float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7296         float FogHeightFade = rsurface.fogheightfade;
7297         float fogfrac;
7298         unsigned int fogmasktableindex;
7299         if (r_refdef.fogplaneviewabove)
7300                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7301         else
7302                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7303         fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7304         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7305 }
7306
7307 void RSurf_UploadBuffersForBatch(void)
7308 {
7309         // 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)
7310         // note that if rsurface.batchvertex3f_vertexbuffer is NULL, dynamicvertex is forced as we don't account for the proper base vertex here.
7311         if (rsurface.batchvertex3f && !rsurface.batchvertex3f_vertexbuffer)
7312                 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
7313         if (rsurface.batchsvector3f && !rsurface.batchsvector3f_vertexbuffer)
7314                 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
7315         if (rsurface.batchtvector3f && !rsurface.batchtvector3f_vertexbuffer)
7316                 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
7317         if (rsurface.batchnormal3f && !rsurface.batchnormal3f_vertexbuffer)
7318                 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
7319         if (rsurface.batchlightmapcolor4f && !rsurface.batchlightmapcolor4f_vertexbuffer)
7320                 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
7321         if (rsurface.batchtexcoordtexture2f && !rsurface.batchtexcoordtexture2f_vertexbuffer)
7322                 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
7323         if (rsurface.batchtexcoordlightmap2f && !rsurface.batchtexcoordlightmap2f_vertexbuffer)
7324                 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
7325         if (rsurface.batchskeletalindex4ub && !rsurface.batchskeletalindex4ub_vertexbuffer)
7326                 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
7327         if (rsurface.batchskeletalweight4ub && !rsurface.batchskeletalweight4ub_vertexbuffer)
7328                 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
7329
7330         if (rsurface.batchelement3s && !rsurface.batchelement3s_indexbuffer)
7331                 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
7332         else if (rsurface.batchelement3i && !rsurface.batchelement3i_indexbuffer)
7333                 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
7334
7335         R_Mesh_VertexPointer(     3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
7336         R_Mesh_ColorPointer(      4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
7337         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
7338         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
7339         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
7340         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
7341         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
7342         R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
7343         R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
7344         R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
7345 }
7346
7347 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7348 {
7349         int i;
7350         for (i = 0;i < numelements;i++)
7351                 outelement3i[i] = inelement3i[i] + adjust;
7352 }
7353
7354 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7355 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7356 {
7357         int deformindex;
7358         int firsttriangle;
7359         int numtriangles;
7360         int firstvertex;
7361         int endvertex;
7362         int numvertices;
7363         int surfacefirsttriangle;
7364         int surfacenumtriangles;
7365         int surfacefirstvertex;
7366         int surfaceendvertex;
7367         int surfacenumvertices;
7368         int batchnumsurfaces = texturenumsurfaces;
7369         int batchnumvertices;
7370         int batchnumtriangles;
7371         int i, j;
7372         qboolean gaps;
7373         qboolean dynamicvertex;
7374         float amplitude;
7375         float animpos;
7376         float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7377         float waveparms[4];
7378         unsigned char *ub;
7379         q3shaderinfo_deform_t *deform;
7380         const msurface_t *surface, *firstsurface;
7381         if (!texturenumsurfaces)
7382                 return;
7383         // find vertex range of this surface batch
7384         gaps = false;
7385         firstsurface = texturesurfacelist[0];
7386         firsttriangle = firstsurface->num_firsttriangle;
7387         batchnumvertices = 0;
7388         batchnumtriangles = 0;
7389         firstvertex = endvertex = firstsurface->num_firstvertex;
7390         for (i = 0;i < texturenumsurfaces;i++)
7391         {
7392                 surface = texturesurfacelist[i];
7393                 if (surface != firstsurface + i)
7394                         gaps = true;
7395                 surfacefirstvertex = surface->num_firstvertex;
7396                 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7397                 surfacenumvertices = surface->num_vertices;
7398                 surfacenumtriangles = surface->num_triangles;
7399                 if (firstvertex > surfacefirstvertex)
7400                         firstvertex = surfacefirstvertex;
7401                 if (endvertex < surfaceendvertex)
7402                         endvertex = surfaceendvertex;
7403                 batchnumvertices += surfacenumvertices;
7404                 batchnumtriangles += surfacenumtriangles;
7405         }
7406
7407         r_refdef.stats[r_stat_batch_batches]++;
7408         if (gaps)
7409                 r_refdef.stats[r_stat_batch_withgaps]++;
7410         r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7411         r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7412         r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7413
7414         // we now know the vertex range used, and if there are any gaps in it
7415         rsurface.batchfirstvertex = firstvertex;
7416         rsurface.batchnumvertices = endvertex - firstvertex;
7417         rsurface.batchfirsttriangle = firsttriangle;
7418         rsurface.batchnumtriangles = batchnumtriangles;
7419
7420         // check if any dynamic vertex processing must occur
7421         dynamicvertex = false;
7422
7423         // we must use vertexbuffers for rendering, we can upload vertex buffers
7424         // easily enough but if the basevertex is non-zero it becomes more
7425         // difficult, so force dynamicvertex path in that case - it's suboptimal
7426         // but the most optimal case is to have the geometry sources provide their
7427         // own anyway.
7428         if (!rsurface.modelvertex3f_vertexbuffer && firstvertex != 0)
7429                 dynamicvertex = true;
7430
7431         // a cvar to force the dynamic vertex path to be taken, for debugging
7432         if (r_batch_debugdynamicvertexpath.integer)
7433         {
7434                 if (!dynamicvertex)
7435                 {
7436                         r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7437                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7438                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7439                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7440                 }
7441                 dynamicvertex = true;
7442         }
7443
7444         // if there is a chance of animated vertex colors, it's a dynamic batch
7445         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
7446         {
7447                 if (!dynamicvertex)
7448                 {
7449                         r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7450                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7451                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7452                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7453                 }
7454                 dynamicvertex = true;
7455         }
7456
7457         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7458         {
7459                 switch (deform->deform)
7460                 {
7461                 default:
7462                 case Q3DEFORM_PROJECTIONSHADOW:
7463                 case Q3DEFORM_TEXT0:
7464                 case Q3DEFORM_TEXT1:
7465                 case Q3DEFORM_TEXT2:
7466                 case Q3DEFORM_TEXT3:
7467                 case Q3DEFORM_TEXT4:
7468                 case Q3DEFORM_TEXT5:
7469                 case Q3DEFORM_TEXT6:
7470                 case Q3DEFORM_TEXT7:
7471                 case Q3DEFORM_NONE:
7472                         break;
7473                 case Q3DEFORM_AUTOSPRITE:
7474                         if (!dynamicvertex)
7475                         {
7476                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7477                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7478                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7479                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7480                         }
7481                         dynamicvertex = true;
7482                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7483                         break;
7484                 case Q3DEFORM_AUTOSPRITE2:
7485                         if (!dynamicvertex)
7486                         {
7487                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7488                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7489                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7490                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7491                         }
7492                         dynamicvertex = true;
7493                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7494                         break;
7495                 case Q3DEFORM_NORMAL:
7496                         if (!dynamicvertex)
7497                         {
7498                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7499                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7500                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7501                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7502                         }
7503                         dynamicvertex = true;
7504                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7505                         break;
7506                 case Q3DEFORM_WAVE:
7507                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7508                                 break; // if wavefunc is a nop, ignore this transform
7509                         if (!dynamicvertex)
7510                         {
7511                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7512                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7513                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7514                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7515                         }
7516                         dynamicvertex = true;
7517                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7518                         break;
7519                 case Q3DEFORM_BULGE:
7520                         if (!dynamicvertex)
7521                         {
7522                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7523                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7524                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7525                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7526                         }
7527                         dynamicvertex = true;
7528                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7529                         break;
7530                 case Q3DEFORM_MOVE:
7531                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7532                                 break; // if wavefunc is a nop, ignore this transform
7533                         if (!dynamicvertex)
7534                         {
7535                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7536                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7537                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7538                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7539                         }
7540                         dynamicvertex = true;
7541                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7542                         break;
7543                 }
7544         }
7545         if (rsurface.texture->materialshaderpass)
7546         {
7547                 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7548                 {
7549                 default:
7550                 case Q3TCGEN_TEXTURE:
7551                         break;
7552                 case Q3TCGEN_LIGHTMAP:
7553                         if (!dynamicvertex)
7554                         {
7555                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7556                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7557                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7558                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7559                         }
7560                         dynamicvertex = true;
7561                         batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7562                         break;
7563                 case Q3TCGEN_VECTOR:
7564                         if (!dynamicvertex)
7565                         {
7566                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7567                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7568                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7569                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7570                         }
7571                         dynamicvertex = true;
7572                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7573                         break;
7574                 case Q3TCGEN_ENVIRONMENT:
7575                         if (!dynamicvertex)
7576                         {
7577                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7578                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7579                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7580                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7581                         }
7582                         dynamicvertex = true;
7583                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7584                         break;
7585                 }
7586                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7587                 {
7588                         if (!dynamicvertex)
7589                         {
7590                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7591                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7592                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7593                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7594                         }
7595                         dynamicvertex = true;
7596                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7597                 }
7598         }
7599
7600         // the caller can specify BATCHNEED_NOGAPS to force a batch with
7601         // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7602         // we ensure this by treating the vertex batch as dynamic...
7603         if ((batchneed & BATCHNEED_ALWAYSCOPY) || ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0)))
7604         {
7605                 if (!dynamicvertex)
7606                 {
7607                         r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7608                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7609                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7610                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7611                 }
7612                 dynamicvertex = true;
7613         }
7614
7615         // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7616         if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7617                 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7618
7619         rsurface.batchvertex3f = rsurface.modelvertex3f;
7620         rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7621         rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7622         rsurface.batchsvector3f = rsurface.modelsvector3f;
7623         rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7624         rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7625         rsurface.batchtvector3f = rsurface.modeltvector3f;
7626         rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7627         rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7628         rsurface.batchnormal3f = rsurface.modelnormal3f;
7629         rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7630         rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7631         rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7632         rsurface.batchlightmapcolor4f_vertexbuffer  = rsurface.modellightmapcolor4f_vertexbuffer;
7633         rsurface.batchlightmapcolor4f_bufferoffset  = rsurface.modellightmapcolor4f_bufferoffset;
7634         rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7635         rsurface.batchtexcoordtexture2f_vertexbuffer  = rsurface.modeltexcoordtexture2f_vertexbuffer;
7636         rsurface.batchtexcoordtexture2f_bufferoffset  = rsurface.modeltexcoordtexture2f_bufferoffset;
7637         rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7638         rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7639         rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7640         rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7641         rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7642         rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7643         rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7644         rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7645         rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7646         rsurface.batchelement3i = rsurface.modelelement3i;
7647         rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7648         rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7649         rsurface.batchelement3s = rsurface.modelelement3s;
7650         rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7651         rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7652         rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7653         rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7654         rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7655         rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7656         rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7657
7658         // if any dynamic vertex processing has to occur in software, we copy the
7659         // entire surface list together before processing to rebase the vertices
7660         // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7661         //
7662         // if any gaps exist and we do not have a static vertex buffer, we have to
7663         // copy the surface list together to avoid wasting upload bandwidth on the
7664         // vertices in the gaps.
7665         //
7666         // if gaps exist and we have a static vertex buffer, we can choose whether
7667         // to combine the index buffer ranges into one dynamic index buffer or
7668         // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7669         //
7670         // in many cases the batch is reduced to one draw call.
7671
7672         rsurface.batchmultidraw = false;
7673         rsurface.batchmultidrawnumsurfaces = 0;
7674         rsurface.batchmultidrawsurfacelist = NULL;
7675
7676         if (!dynamicvertex)
7677         {
7678                 // static vertex data, just set pointers...
7679                 rsurface.batchgeneratedvertex = false;
7680                 // if there are gaps, we want to build a combined index buffer,
7681                 // otherwise use the original static buffer with an appropriate offset
7682                 if (gaps)
7683                 {
7684                         r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7685                         r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7686                         r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7687                         r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7688                         if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7689                         {
7690                                 rsurface.batchmultidraw = true;
7691                                 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7692                                 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7693                                 return;
7694                         }
7695                         // build a new triangle elements array for this batch
7696                         rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7697                         rsurface.batchfirsttriangle = 0;
7698                         numtriangles = 0;
7699                         for (i = 0;i < texturenumsurfaces;i++)
7700                         {
7701                                 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7702                                 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7703                                 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7704                                 numtriangles += surfacenumtriangles;
7705                         }
7706                         rsurface.batchelement3i_indexbuffer = NULL;
7707                         rsurface.batchelement3i_bufferoffset = 0;
7708                         rsurface.batchelement3s = NULL;
7709                         rsurface.batchelement3s_indexbuffer = NULL;
7710                         rsurface.batchelement3s_bufferoffset = 0;
7711                         if (endvertex <= 65536)
7712                         {
7713                                 // make a 16bit (unsigned short) index array if possible
7714                                 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7715                                 for (i = 0;i < numtriangles*3;i++)
7716                                         rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7717                         }
7718                 }
7719                 else
7720                 {
7721                         r_refdef.stats[r_stat_batch_fast_batches] += 1;
7722                         r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
7723                         r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
7724                         r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
7725                 }
7726                 return;
7727         }
7728
7729         // something needs software processing, do it for real...
7730         // we only directly handle separate array data in this case and then
7731         // generate interleaved data if needed...
7732         rsurface.batchgeneratedvertex = true;
7733         r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
7734         r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
7735         r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
7736         r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
7737
7738         // now copy the vertex data into a combined array and make an index array
7739         // (this is what Quake3 does all the time)
7740         // we also apply any skeletal animation here that would have been done in
7741         // the vertex shader, because most of the dynamic vertex animation cases
7742         // need actual vertex positions and normals
7743         //if (dynamicvertex)
7744         {
7745                 rsurface.batchvertex3f = NULL;
7746                 rsurface.batchvertex3f_vertexbuffer = NULL;
7747                 rsurface.batchvertex3f_bufferoffset = 0;
7748                 rsurface.batchsvector3f = NULL;
7749                 rsurface.batchsvector3f_vertexbuffer = NULL;
7750                 rsurface.batchsvector3f_bufferoffset = 0;
7751                 rsurface.batchtvector3f = NULL;
7752                 rsurface.batchtvector3f_vertexbuffer = NULL;
7753                 rsurface.batchtvector3f_bufferoffset = 0;
7754                 rsurface.batchnormal3f = NULL;
7755                 rsurface.batchnormal3f_vertexbuffer = NULL;
7756                 rsurface.batchnormal3f_bufferoffset = 0;
7757                 rsurface.batchlightmapcolor4f = NULL;
7758                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7759                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7760                 rsurface.batchtexcoordtexture2f = NULL;
7761                 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7762                 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7763                 rsurface.batchtexcoordlightmap2f = NULL;
7764                 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7765                 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7766                 rsurface.batchskeletalindex4ub = NULL;
7767                 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7768                 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7769                 rsurface.batchskeletalweight4ub = NULL;
7770                 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7771                 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7772                 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7773                 rsurface.batchelement3i_indexbuffer = NULL;
7774                 rsurface.batchelement3i_bufferoffset = 0;
7775                 rsurface.batchelement3s = NULL;
7776                 rsurface.batchelement3s_indexbuffer = NULL;
7777                 rsurface.batchelement3s_bufferoffset = 0;
7778                 rsurface.batchskeletaltransform3x4buffer = NULL;
7779                 rsurface.batchskeletaltransform3x4offset = 0;
7780                 rsurface.batchskeletaltransform3x4size = 0;
7781                 // we'll only be setting up certain arrays as needed
7782                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7783                         rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7784                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7785                         rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7786                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7787                 {
7788                         rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7789                         rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7790                 }
7791                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7792                         rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
7793                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7794                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7795                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7796                         rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7797                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7798                 {
7799                         rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7800                         rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7801                 }
7802                 numvertices = 0;
7803                 numtriangles = 0;
7804                 for (i = 0;i < texturenumsurfaces;i++)
7805                 {
7806                         surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
7807                         surfacenumvertices = texturesurfacelist[i]->num_vertices;
7808                         surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7809                         surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7810                         // copy only the data requested
7811                         if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
7812                         {
7813                                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7814                                 {
7815                                         if (rsurface.batchvertex3f)
7816                                                 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7817                                         else
7818                                                 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7819                                 }
7820                                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7821                                 {
7822                                         if (rsurface.modelnormal3f)
7823                                                 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7824                                         else
7825                                                 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7826                                 }
7827                                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7828                                 {
7829                                         if (rsurface.modelsvector3f)
7830                                         {
7831                                                 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7832                                                 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7833                                         }
7834                                         else
7835                                         {
7836                                                 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7837                                                 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7838                                         }
7839                                 }
7840                                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7841                                 {
7842                                         if (rsurface.modellightmapcolor4f)
7843                                                 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
7844                                         else
7845                                                 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
7846                                 }
7847                                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7848                                 {
7849                                         if (rsurface.modeltexcoordtexture2f)
7850                                                 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7851                                         else
7852                                                 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7853                                 }
7854                                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7855                                 {
7856                                         if (rsurface.modeltexcoordlightmap2f)
7857                                                 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7858                                         else
7859                                                 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7860                                 }
7861                                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7862                                 {
7863                                         if (rsurface.modelskeletalindex4ub)
7864                                         {
7865                                                 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7866                                                 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7867                                         }
7868                                         else
7869                                         {
7870                                                 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7871                                                 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7872                                                 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
7873                                                 for (j = 0;j < surfacenumvertices;j++)
7874                                                         ub[j*4] = 255;
7875                                         }
7876                                 }
7877                         }
7878                         RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
7879                         numvertices += surfacenumvertices;
7880                         numtriangles += surfacenumtriangles;
7881                 }
7882
7883                 // generate a 16bit index array as well if possible
7884                 // (in general, dynamic batches fit)
7885                 if (numvertices <= 65536)
7886                 {
7887                         rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7888                         for (i = 0;i < numtriangles*3;i++)
7889                                 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7890                 }
7891
7892                 // since we've copied everything, the batch now starts at 0
7893                 rsurface.batchfirstvertex = 0;
7894                 rsurface.batchnumvertices = batchnumvertices;
7895                 rsurface.batchfirsttriangle = 0;
7896                 rsurface.batchnumtriangles = batchnumtriangles;
7897         }
7898
7899         // apply skeletal animation that would have been done in the vertex shader
7900         if (rsurface.batchskeletaltransform3x4)
7901         {
7902                 const unsigned char *si;
7903                 const unsigned char *sw;
7904                 const float *t[4];
7905                 const float *b = rsurface.batchskeletaltransform3x4;
7906                 float *vp, *vs, *vt, *vn;
7907                 float w[4];
7908                 float m[3][4], n[3][4];
7909                 float tp[3], ts[3], tt[3], tn[3];
7910                 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
7911                 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
7912                 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
7913                 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
7914                 si = rsurface.batchskeletalindex4ub;
7915                 sw = rsurface.batchskeletalweight4ub;
7916                 vp = rsurface.batchvertex3f;
7917                 vs = rsurface.batchsvector3f;
7918                 vt = rsurface.batchtvector3f;
7919                 vn = rsurface.batchnormal3f;
7920                 memset(m[0], 0, sizeof(m));
7921                 memset(n[0], 0, sizeof(n));
7922                 for (i = 0;i < batchnumvertices;i++)
7923                 {
7924                         t[0] = b + si[0]*12;
7925                         if (sw[0] == 255)
7926                         {
7927                                 // common case - only one matrix
7928                                 m[0][0] = t[0][ 0];
7929                                 m[0][1] = t[0][ 1];
7930                                 m[0][2] = t[0][ 2];
7931                                 m[0][3] = t[0][ 3];
7932                                 m[1][0] = t[0][ 4];
7933                                 m[1][1] = t[0][ 5];
7934                                 m[1][2] = t[0][ 6];
7935                                 m[1][3] = t[0][ 7];
7936                                 m[2][0] = t[0][ 8];
7937                                 m[2][1] = t[0][ 9];
7938                                 m[2][2] = t[0][10];
7939                                 m[2][3] = t[0][11];
7940                         }
7941                         else if (sw[2] + sw[3])
7942                         {
7943                                 // blend 4 matrices
7944                                 t[1] = b + si[1]*12;
7945                                 t[2] = b + si[2]*12;
7946                                 t[3] = b + si[3]*12;
7947                                 w[0] = sw[0] * (1.0f / 255.0f);
7948                                 w[1] = sw[1] * (1.0f / 255.0f);
7949                                 w[2] = sw[2] * (1.0f / 255.0f);
7950                                 w[3] = sw[3] * (1.0f / 255.0f);
7951                                 // blend the matrices
7952                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
7953                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
7954                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
7955                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
7956                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
7957                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
7958                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
7959                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
7960                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
7961                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
7962                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
7963                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
7964                         }
7965                         else
7966                         {
7967                                 // blend 2 matrices
7968                                 t[1] = b + si[1]*12;
7969                                 w[0] = sw[0] * (1.0f / 255.0f);
7970                                 w[1] = sw[1] * (1.0f / 255.0f);
7971                                 // blend the matrices
7972                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
7973                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
7974                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
7975                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
7976                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
7977                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
7978                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
7979                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
7980                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
7981                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
7982                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
7983                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
7984                         }
7985                         si += 4;
7986                         sw += 4;
7987                         // modify the vertex
7988                         VectorCopy(vp, tp);
7989                         vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
7990                         vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
7991                         vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
7992                         vp += 3;
7993                         if (vn)
7994                         {
7995                                 // the normal transformation matrix is a set of cross products...
7996                                 CrossProduct(m[1], m[2], n[0]);
7997                                 CrossProduct(m[2], m[0], n[1]);
7998                                 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
7999                                 VectorCopy(vn, tn);
8000                                 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8001                                 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8002                                 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8003                                 VectorNormalize(vn);
8004                                 vn += 3;
8005                                 if (vs)
8006                                 {
8007                                         VectorCopy(vs, ts);
8008                                         vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8009                                         vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8010                                         vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8011                                         VectorNormalize(vs);
8012                                         vs += 3;
8013                                         VectorCopy(vt, tt);
8014                                         vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8015                                         vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8016                                         vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8017                                         VectorNormalize(vt);
8018                                         vt += 3;
8019                                 }
8020                         }
8021                 }
8022                 rsurface.batchskeletaltransform3x4 = NULL;
8023                 rsurface.batchskeletalnumtransforms = 0;
8024         }
8025
8026         // q1bsp surfaces rendered in vertex color mode have to have colors
8027         // calculated based on lightstyles
8028         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
8029         {
8030                 // generate color arrays for the surfaces in this list
8031                 int c[4];
8032                 int scale;
8033                 int size3;
8034                 const int *offsets;
8035                 const unsigned char *lm;
8036                 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8037                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8038                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8039                 numvertices = 0;
8040                 for (i = 0;i < texturenumsurfaces;i++)
8041                 {
8042                         surface = texturesurfacelist[i];
8043                         offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8044                         surfacenumvertices = surface->num_vertices;
8045                         if (surface->lightmapinfo->samples)
8046                         {
8047                                 for (j = 0;j < surfacenumvertices;j++)
8048                                 {
8049                                         lm = surface->lightmapinfo->samples + offsets[j];
8050                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8051                                         VectorScale(lm, scale, c);
8052                                         if (surface->lightmapinfo->styles[1] != 255)
8053                                         {
8054                                                 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8055                                                 lm += size3;
8056                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8057                                                 VectorMA(c, scale, lm, c);
8058                                                 if (surface->lightmapinfo->styles[2] != 255)
8059                                                 {
8060                                                         lm += size3;
8061                                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8062                                                         VectorMA(c, scale, lm, c);
8063                                                         if (surface->lightmapinfo->styles[3] != 255)
8064                                                         {
8065                                                                 lm += size3;
8066                                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8067                                                                 VectorMA(c, scale, lm, c);
8068                                                         }
8069                                                 }
8070                                         }
8071                                         c[0] >>= 7;
8072                                         c[1] >>= 7;
8073                                         c[2] >>= 7;
8074                                         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);
8075                                         numvertices++;
8076                                 }
8077                         }
8078                         else
8079                         {
8080                                 for (j = 0;j < surfacenumvertices;j++)
8081                                 {
8082                                         Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8083                                         numvertices++;
8084                                 }
8085                         }
8086                 }
8087         }
8088
8089         // if vertices are deformed (sprite flares and things in maps, possibly
8090         // water waves, bulges and other deformations), modify the copied vertices
8091         // in place
8092         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8093         {
8094                 float scale;
8095                 switch (deform->deform)
8096                 {
8097                 default:
8098                 case Q3DEFORM_PROJECTIONSHADOW:
8099                 case Q3DEFORM_TEXT0:
8100                 case Q3DEFORM_TEXT1:
8101                 case Q3DEFORM_TEXT2:
8102                 case Q3DEFORM_TEXT3:
8103                 case Q3DEFORM_TEXT4:
8104                 case Q3DEFORM_TEXT5:
8105                 case Q3DEFORM_TEXT6:
8106                 case Q3DEFORM_TEXT7:
8107                 case Q3DEFORM_NONE:
8108                         break;
8109                 case Q3DEFORM_AUTOSPRITE:
8110                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8111                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8112                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8113                         VectorNormalize(newforward);
8114                         VectorNormalize(newright);
8115                         VectorNormalize(newup);
8116 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8117 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8118 //                      rsurface.batchvertex3f_bufferoffset = 0;
8119 //                      rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8120 //                      rsurface.batchsvector3f_vertexbuffer = NULL;
8121 //                      rsurface.batchsvector3f_bufferoffset = 0;
8122 //                      rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8123 //                      rsurface.batchtvector3f_vertexbuffer = NULL;
8124 //                      rsurface.batchtvector3f_bufferoffset = 0;
8125 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8126 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8127 //                      rsurface.batchnormal3f_bufferoffset = 0;
8128                         // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8129                         if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8130                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8131                         if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8132                                 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);
8133                         // a single autosprite surface can contain multiple sprites...
8134                         for (j = 0;j < batchnumvertices - 3;j += 4)
8135                         {
8136                                 VectorClear(center);
8137                                 for (i = 0;i < 4;i++)
8138                                         VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8139                                 VectorScale(center, 0.25f, center);
8140                                 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8141                                 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8142                                 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8143                                 for (i = 0;i < 4;i++)
8144                                 {
8145                                         VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8146                                         VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8147                                 }
8148                         }
8149                         // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8150                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8151                         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);
8152                         break;
8153                 case Q3DEFORM_AUTOSPRITE2:
8154                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8155                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8156                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8157                         VectorNormalize(newforward);
8158                         VectorNormalize(newright);
8159                         VectorNormalize(newup);
8160 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8161 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8162 //                      rsurface.batchvertex3f_bufferoffset = 0;
8163                         {
8164                                 const float *v1, *v2;
8165                                 vec3_t start, end;
8166                                 float f, l;
8167                                 struct
8168                                 {
8169                                         float length2;
8170                                         const float *v1;
8171                                         const float *v2;
8172                                 }
8173                                 shortest[2];
8174                                 memset(shortest, 0, sizeof(shortest));
8175                                 // a single autosprite surface can contain multiple sprites...
8176                                 for (j = 0;j < batchnumvertices - 3;j += 4)
8177                                 {
8178                                         VectorClear(center);
8179                                         for (i = 0;i < 4;i++)
8180                                                 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8181                                         VectorScale(center, 0.25f, center);
8182                                         // find the two shortest edges, then use them to define the
8183                                         // axis vectors for rotating around the central axis
8184                                         for (i = 0;i < 6;i++)
8185                                         {
8186                                                 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8187                                                 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8188                                                 l = VectorDistance2(v1, v2);
8189                                                 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8190                                                 if (v1[2] != v2[2])
8191                                                         l += (1.0f / 1024.0f);
8192                                                 if (shortest[0].length2 > l || i == 0)
8193                                                 {
8194                                                         shortest[1] = shortest[0];
8195                                                         shortest[0].length2 = l;
8196                                                         shortest[0].v1 = v1;
8197                                                         shortest[0].v2 = v2;
8198                                                 }
8199                                                 else if (shortest[1].length2 > l || i == 1)
8200                                                 {
8201                                                         shortest[1].length2 = l;
8202                                                         shortest[1].v1 = v1;
8203                                                         shortest[1].v2 = v2;
8204                                                 }
8205                                         }
8206                                         VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8207                                         VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8208                                         // this calculates the right vector from the shortest edge
8209                                         // and the up vector from the edge midpoints
8210                                         VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8211                                         VectorNormalize(right);
8212                                         VectorSubtract(end, start, up);
8213                                         VectorNormalize(up);
8214                                         // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8215                                         VectorSubtract(rsurface.localvieworigin, center, forward);
8216                                         //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8217                                         VectorNegate(forward, forward);
8218                                         VectorReflect(forward, 0, up, forward);
8219                                         VectorNormalize(forward);
8220                                         CrossProduct(up, forward, newright);
8221                                         VectorNormalize(newright);
8222                                         // rotate the quad around the up axis vector, this is made
8223                                         // especially easy by the fact we know the quad is flat,
8224                                         // so we only have to subtract the center position and
8225                                         // measure distance along the right vector, and then
8226                                         // multiply that by the newright vector and add back the
8227                                         // center position
8228                                         // we also need to subtract the old position to undo the
8229                                         // displacement from the center, which we do with a
8230                                         // DotProduct, the subtraction/addition of center is also
8231                                         // optimized into DotProducts here
8232                                         l = DotProduct(right, center);
8233                                         for (i = 0;i < 4;i++)
8234                                         {
8235                                                 v1 = rsurface.batchvertex3f + 3*(j+i);
8236                                                 f = DotProduct(right, v1) - l;
8237                                                 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8238                                         }
8239                                 }
8240                         }
8241                         if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8242                         {
8243 //                              rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8244 //                              rsurface.batchnormal3f_vertexbuffer = NULL;
8245 //                              rsurface.batchnormal3f_bufferoffset = 0;
8246                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8247                         }
8248                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8249                         {
8250 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8251 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8252 //                              rsurface.batchsvector3f_bufferoffset = 0;
8253 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8254 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8255 //                              rsurface.batchtvector3f_bufferoffset = 0;
8256                                 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);
8257                         }
8258                         break;
8259                 case Q3DEFORM_NORMAL:
8260                         // deform the normals to make reflections wavey
8261                         rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8262                         rsurface.batchnormal3f_vertexbuffer = NULL;
8263                         rsurface.batchnormal3f_bufferoffset = 0;
8264                         for (j = 0;j < batchnumvertices;j++)
8265                         {
8266                                 float vertex[3];
8267                                 float *normal = rsurface.batchnormal3f + 3*j;
8268                                 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8269                                 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8270                                 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8271                                 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8272                                 VectorNormalize(normal);
8273                         }
8274                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8275                         {
8276 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8277 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8278 //                              rsurface.batchsvector3f_bufferoffset = 0;
8279 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8280 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8281 //                              rsurface.batchtvector3f_bufferoffset = 0;
8282                                 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);
8283                         }
8284                         break;
8285                 case Q3DEFORM_WAVE:
8286                         // deform vertex array to make wavey water and flags and such
8287                         waveparms[0] = deform->waveparms[0];
8288                         waveparms[1] = deform->waveparms[1];
8289                         waveparms[2] = deform->waveparms[2];
8290                         waveparms[3] = deform->waveparms[3];
8291                         if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8292                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8293                         // this is how a divisor of vertex influence on deformation
8294                         animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8295                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8296 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8297 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8298 //                      rsurface.batchvertex3f_bufferoffset = 0;
8299 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8300 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8301 //                      rsurface.batchnormal3f_bufferoffset = 0;
8302                         for (j = 0;j < batchnumvertices;j++)
8303                         {
8304                                 // if the wavefunc depends on time, evaluate it per-vertex
8305                                 if (waveparms[3])
8306                                 {
8307                                         waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8308                                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8309                                 }
8310                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8311                         }
8312                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8313                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8314                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8315                         {
8316 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8317 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8318 //                              rsurface.batchsvector3f_bufferoffset = 0;
8319 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8320 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8321 //                              rsurface.batchtvector3f_bufferoffset = 0;
8322                                 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);
8323                         }
8324                         break;
8325                 case Q3DEFORM_BULGE:
8326                         // deform vertex array to make the surface have moving bulges
8327 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8328 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8329 //                      rsurface.batchvertex3f_bufferoffset = 0;
8330 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8331 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8332 //                      rsurface.batchnormal3f_bufferoffset = 0;
8333                         for (j = 0;j < batchnumvertices;j++)
8334                         {
8335                                 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8336                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8337                         }
8338                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8339                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8340                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8341                         {
8342 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8343 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8344 //                              rsurface.batchsvector3f_bufferoffset = 0;
8345 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8346 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8347 //                              rsurface.batchtvector3f_bufferoffset = 0;
8348                                 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);
8349                         }
8350                         break;
8351                 case Q3DEFORM_MOVE:
8352                         // deform vertex array
8353                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8354                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8355                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8356                         VectorScale(deform->parms, scale, waveparms);
8357 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8358 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8359 //                      rsurface.batchvertex3f_bufferoffset = 0;
8360                         for (j = 0;j < batchnumvertices;j++)
8361                                 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8362                         break;
8363                 }
8364         }
8365
8366         if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8367         {
8368         // generate texcoords based on the chosen texcoord source
8369                 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8370                 {
8371                 default:
8372                 case Q3TCGEN_TEXTURE:
8373                         break;
8374                 case Q3TCGEN_LIGHTMAP:
8375         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8376         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8377         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8378                         if (rsurface.batchtexcoordlightmap2f)
8379                                 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8380                         break;
8381                 case Q3TCGEN_VECTOR:
8382         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8383         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8384         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8385                         for (j = 0;j < batchnumvertices;j++)
8386                         {
8387                                 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8388                                 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8389                         }
8390                         break;
8391                 case Q3TCGEN_ENVIRONMENT:
8392                         // make environment reflections using a spheremap
8393                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8394                         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8395                         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8396                         for (j = 0;j < batchnumvertices;j++)
8397                         {
8398                                 // identical to Q3A's method, but executed in worldspace so
8399                                 // carried models can be shiny too
8400
8401                                 float viewer[3], d, reflected[3], worldreflected[3];
8402
8403                                 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8404                                 // VectorNormalize(viewer);
8405
8406                                 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8407
8408                                 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8409                                 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8410                                 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8411                                 // note: this is proportinal to viewer, so we can normalize later
8412
8413                                 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8414                                 VectorNormalize(worldreflected);
8415
8416                                 // note: this sphere map only uses world x and z!
8417                                 // so positive and negative y will LOOK THE SAME.
8418                                 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8419                                 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8420                         }
8421                         break;
8422                 }
8423                 // the only tcmod that needs software vertex processing is turbulent, so
8424                 // check for it here and apply the changes if needed
8425                 // and we only support that as the first one
8426                 // (handling a mixture of turbulent and other tcmods would be problematic
8427                 //  without punting it entirely to a software path)
8428                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8429                 {
8430                         amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8431                         animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8432         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8433         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8434         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8435                         for (j = 0;j < batchnumvertices;j++)
8436                         {
8437                                 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);
8438                                 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8439                         }
8440                 }
8441         }
8442 }
8443
8444 void RSurf_DrawBatch(void)
8445 {
8446         // sometimes a zero triangle surface (usually a degenerate patch) makes it
8447         // through the pipeline, killing it earlier in the pipeline would have
8448         // per-surface overhead rather than per-batch overhead, so it's best to
8449         // reject it here, before it hits glDraw.
8450         if (rsurface.batchnumtriangles == 0)
8451                 return;
8452 #if 0
8453         // batch debugging code
8454         if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8455         {
8456                 int i;
8457                 int j;
8458                 int c;
8459                 const int *e;
8460                 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8461                 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8462                 {
8463                         c = e[i];
8464                         for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8465                         {
8466                                 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8467                                 {
8468                                         if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8469                                                 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);
8470                                         break;
8471                                 }
8472                         }
8473                 }
8474         }
8475 #endif
8476         if (rsurface.batchmultidraw)
8477         {
8478                 // issue multiple draws rather than copying index data
8479                 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8480                 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8481                 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8482                 for (i = 0;i < numsurfaces;)
8483                 {
8484                         // combine consecutive surfaces as one draw
8485                         for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8486                                 if (surfacelist[j] != surfacelist[k] + 1)
8487                                         break;
8488                         firstvertex = surfacelist[i]->num_firstvertex;
8489                         endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8490                         firsttriangle = surfacelist[i]->num_firsttriangle;
8491                         endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8492                         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);
8493                         i = j;
8494                 }
8495         }
8496         else
8497         {
8498                 // there is only one consecutive run of index data (may have been combined)
8499                 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);
8500         }
8501 }
8502
8503 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8504 {
8505         // pick the closest matching water plane
8506         int planeindex, vertexindex, bestplaneindex = -1;
8507         float d, bestd;
8508         vec3_t vert;
8509         const float *v;
8510         r_waterstate_waterplane_t *p;
8511         qboolean prepared = false;
8512         bestd = 0;
8513         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8514         {
8515                 if(p->camera_entity != rsurface.texture->camera_entity)
8516                         continue;
8517                 d = 0;
8518                 if(!prepared)
8519                 {
8520                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8521                         prepared = true;
8522                         if(rsurface.batchnumvertices == 0)
8523                                 break;
8524                 }
8525                 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8526                 {
8527                         Matrix4x4_Transform(&rsurface.matrix, v, vert);
8528                         d += fabs(PlaneDiff(vert, &p->plane));
8529                 }
8530                 if (bestd > d || bestplaneindex < 0)
8531                 {
8532                         bestd = d;
8533                         bestplaneindex = planeindex;
8534                 }
8535         }
8536         return bestplaneindex;
8537         // NOTE: this MAY return a totally unrelated water plane; we can ignore
8538         // this situation though, as it might be better to render single larger
8539         // batches with useless stuff (backface culled for example) than to
8540         // render multiple smaller batches
8541 }
8542
8543 void RSurf_SetupDepthAndCulling(void)
8544 {
8545         // submodels are biased to avoid z-fighting with world surfaces that they
8546         // may be exactly overlapping (avoids z-fighting artifacts on certain
8547         // doors and things in Quake maps)
8548         GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8549         GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8550         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8551         GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8552 }
8553
8554 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8555 {
8556         int i, j;
8557         // transparent sky would be ridiculous
8558         if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8559                 return;
8560         R_SetupShader_Generic_NoTexture(false, false);
8561         skyrenderlater = true;
8562         RSurf_SetupDepthAndCulling();
8563         GL_DepthMask(true);
8564
8565         // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8566         if (r_sky_scissor.integer)
8567         {
8568                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8569                 for (i = 0; i < texturenumsurfaces; i++)
8570                 {
8571                         const msurface_t *surf = texturesurfacelist[i];
8572                         const float *v;
8573                         float p[3];
8574                         float mins[3], maxs[3];
8575                         int scissor[4];
8576                         for (j = 0, v = rsurface.batchvertex3f + 3 * surf->num_firstvertex; j < surf->num_vertices; j++, v += 3)
8577                         {
8578                                 Matrix4x4_Transform(&rsurface.matrix, v, p);
8579                                 if (j > 0)
8580                                 {
8581                                         if (mins[0] > p[0]) mins[0] = p[0];
8582                                         if (mins[1] > p[1]) mins[1] = p[1];
8583                                         if (mins[2] > p[2]) mins[2] = p[2];
8584                                         if (maxs[0] < p[0]) maxs[0] = p[0];
8585                                         if (maxs[1] < p[1]) maxs[1] = p[1];
8586                                         if (maxs[2] < p[2]) maxs[2] = p[2];
8587                                 }
8588                                 else
8589                                 {
8590                                         VectorCopy(p, mins);
8591                                         VectorCopy(p, maxs);
8592                                 }
8593                         }
8594                         if (!R_ScissorForBBox(mins, maxs, scissor))
8595                         {
8596                                 if (skyscissor[2])
8597                                 {
8598                                         if (skyscissor[0] > scissor[0])
8599                                         {
8600                                                 skyscissor[2] += skyscissor[0] - scissor[0];
8601                                                 skyscissor[0] = scissor[0];
8602                                         }
8603                                         if (skyscissor[1] > scissor[1])
8604                                         {
8605                                                 skyscissor[3] += skyscissor[1] - scissor[1];
8606                                                 skyscissor[1] = scissor[1];
8607                                         }
8608                                         if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8609                                                 skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8610                                         if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8611                                                 skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8612                                 }
8613                                 else
8614                                         Vector4Copy(scissor, skyscissor);
8615                         }
8616                 }
8617         }
8618
8619         // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8620         // skymasking on them, and Quake3 never did sky masking (unlike
8621         // software Quake and software Quake2), so disable the sky masking
8622         // in Quake3 maps as it causes problems with q3map2 sky tricks,
8623         // and skymasking also looks very bad when noclipping outside the
8624         // level, so don't use it then either.
8625         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)
8626         {
8627                 R_Mesh_ResetTextureState();
8628                 if (skyrendermasked)
8629                 {
8630                         R_SetupShader_DepthOrShadow(false, false, false);
8631                         // depth-only (masking)
8632                         GL_ColorMask(0, 0, 0, 0);
8633                         // just to make sure that braindead drivers don't draw
8634                         // anything despite that colormask...
8635                         GL_BlendFunc(GL_ZERO, GL_ONE);
8636                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8637                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8638                 }
8639                 else
8640                 {
8641                         R_SetupShader_Generic_NoTexture(false, false);
8642                         // fog sky
8643                         GL_BlendFunc(GL_ONE, GL_ZERO);
8644                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8645                         GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
8646                         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
8647                 }
8648                 RSurf_DrawBatch();
8649                 if (skyrendermasked)
8650                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8651         }
8652         R_Mesh_ResetTextureState();
8653         GL_Color(1, 1, 1, 1);
8654 }
8655
8656 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
8657 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
8658 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass, qboolean ui)
8659 {
8660         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
8661                 return;
8662         if (prepass)
8663         {
8664                 // render screenspace normalmap to texture
8665                 GL_DepthMask(true);
8666                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false);
8667                 RSurf_DrawBatch();
8668                 return;
8669         }
8670
8671         // bind lightmap texture
8672
8673         // water/refraction/reflection/camera surfaces have to be handled specially
8674         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
8675         {
8676                 int start, end, startplaneindex;
8677                 for (start = 0;start < texturenumsurfaces;start = end)
8678                 {
8679                         startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
8680                         if(startplaneindex < 0)
8681                         {
8682                                 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
8683                                 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
8684                                 end = start + 1;
8685                                 continue;
8686                         }
8687                         for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
8688                                 ;
8689                         // now that we have a batch using the same planeindex, render it
8690                         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
8691                         {
8692                                 // render water or distortion background
8693                                 GL_DepthMask(true);
8694                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8695                                 RSurf_DrawBatch();
8696                                 // blend surface on top
8697                                 GL_DepthMask(false);
8698                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false);
8699                                 RSurf_DrawBatch();
8700                         }
8701                         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
8702                         {
8703                                 // render surface with reflection texture as input
8704                                 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8705                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8706                                 RSurf_DrawBatch();
8707                         }
8708                 }
8709                 return;
8710         }
8711
8712         // render surface batch normally
8713         GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8714         R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0 || ui);
8715         RSurf_DrawBatch();
8716 }
8717
8718 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
8719 {
8720         int vi;
8721         int j;
8722         int texturesurfaceindex;
8723         int k;
8724         const msurface_t *surface;
8725         float surfacecolor4f[4];
8726
8727 //      R_Mesh_ResetTextureState();
8728         R_SetupShader_Generic_NoTexture(false, false);
8729
8730         GL_BlendFunc(GL_ONE, GL_ZERO);
8731         GL_DepthMask(writedepth);
8732
8733         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
8734         vi = 0;
8735         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8736         {
8737                 surface = texturesurfacelist[texturesurfaceindex];
8738                 k = (int)(((size_t)surface) / sizeof(msurface_t));
8739                 Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
8740                 for (j = 0;j < surface->num_vertices;j++)
8741                 {
8742                         Vector4Copy(surfacecolor4f, rsurface.batchlightmapcolor4f + 4 * vi);
8743                         vi++;
8744                 }
8745         }
8746         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchlightmapcolor4f, rsurface.batchtexcoordtexture2f);
8747         RSurf_DrawBatch();
8748 }
8749
8750 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass, qboolean ui)
8751 {
8752         CHECKGLERROR
8753         RSurf_SetupDepthAndCulling();
8754         if (r_showsurfaces.integer && r_refdef.view.showdebug)
8755         {
8756                 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
8757                 return;
8758         }
8759         switch (vid.renderpath)
8760         {
8761         case RENDERPATH_GL32:
8762         case RENDERPATH_GLES2:
8763                 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8764                 break;
8765         }
8766         CHECKGLERROR
8767 }
8768
8769 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
8770 {
8771         int i, j;
8772         int texturenumsurfaces, endsurface;
8773         texture_t *texture;
8774         const msurface_t *surface;
8775         const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
8776
8777         RSurf_ActiveModelEntity(ent, true, true, false);
8778
8779         if (r_transparentdepthmasking.integer)
8780         {
8781                 qboolean setup = false;
8782                 for (i = 0;i < numsurfaces;i = j)
8783                 {
8784                         j = i + 1;
8785                         surface = rsurface.modelsurfaces + surfacelist[i];
8786                         texture = surface->texture;
8787                         rsurface.texture = R_GetCurrentTexture(texture);
8788                         rsurface.lightmaptexture = NULL;
8789                         rsurface.deluxemaptexture = NULL;
8790                         rsurface.uselightmaptexture = false;
8791                         // scan ahead until we find a different texture
8792                         endsurface = min(i + 1024, numsurfaces);
8793                         texturenumsurfaces = 0;
8794                         texturesurfacelist[texturenumsurfaces++] = surface;
8795                         for (;j < endsurface;j++)
8796                         {
8797                                 surface = rsurface.modelsurfaces + surfacelist[j];
8798                                 if (texture != surface->texture)
8799                                         break;
8800                                 texturesurfacelist[texturenumsurfaces++] = surface;
8801                         }
8802                         if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
8803                                 continue;
8804                         // render the range of surfaces as depth
8805                         if (!setup)
8806                         {
8807                                 setup = true;
8808                                 GL_ColorMask(0,0,0,0);
8809                                 GL_Color(1,1,1,1);
8810                                 GL_DepthTest(true);
8811                                 GL_BlendFunc(GL_ONE, GL_ZERO);
8812                                 GL_DepthMask(true);
8813 //                              R_Mesh_ResetTextureState();
8814                         }
8815                         RSurf_SetupDepthAndCulling();
8816                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8817                         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8818                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8819                         RSurf_DrawBatch();
8820                 }
8821                 if (setup)
8822                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8823         }
8824
8825         for (i = 0;i < numsurfaces;i = j)
8826         {
8827                 j = i + 1;
8828                 surface = rsurface.modelsurfaces + surfacelist[i];
8829                 texture = surface->texture;
8830                 rsurface.texture = R_GetCurrentTexture(texture);
8831                 // scan ahead until we find a different texture
8832                 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
8833                 texturenumsurfaces = 0;
8834                 texturesurfacelist[texturenumsurfaces++] = surface;
8835                         rsurface.lightmaptexture = surface->lightmaptexture;
8836                         rsurface.deluxemaptexture = surface->deluxemaptexture;
8837                         rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
8838                         for (;j < endsurface;j++)
8839                         {
8840                                 surface = rsurface.modelsurfaces + surfacelist[j];
8841                                 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
8842                                         break;
8843                                 texturesurfacelist[texturenumsurfaces++] = surface;
8844                         }
8845                 // render the range of surfaces
8846                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false, false);
8847         }
8848         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
8849 }
8850
8851 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8852 {
8853         // transparent surfaces get pushed off into the transparent queue
8854         int surfacelistindex;
8855         const msurface_t *surface;
8856         vec3_t tempcenter, center;
8857         for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
8858         {
8859                 surface = texturesurfacelist[surfacelistindex];
8860                 if (r_transparent_sortsurfacesbynearest.integer)
8861                 {
8862                         tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
8863                         tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
8864                         tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
8865                 }
8866                 else
8867                 {
8868                         tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
8869                         tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
8870                         tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
8871                 }
8872                 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
8873                 if (rsurface.entity->transparent_offset) // transparent offset
8874                 {
8875                         center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
8876                         center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
8877                         center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
8878                 }
8879                 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);
8880         }
8881 }
8882
8883 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8884 {
8885         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
8886                 return;
8887         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
8888                 return;
8889         RSurf_SetupDepthAndCulling();
8890         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8891         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8892         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8893         RSurf_DrawBatch();
8894 }
8895
8896 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass, qboolean ui)
8897 {
8898         CHECKGLERROR
8899         if (ui)
8900                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8901         else if (depthonly)
8902                 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
8903         else if (prepass)
8904         {
8905                 if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
8906                         return;
8907                 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8908                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
8909                 else
8910                         R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8911         }
8912         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
8913                 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
8914         else if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
8915                 return;
8916         else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
8917         {
8918                 // in the deferred case, transparent surfaces were queued during prepass
8919                 if (!r_shadow_usingdeferredprepass)
8920                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
8921         }
8922         else
8923         {
8924                 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
8925                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass, ui);
8926         }
8927         CHECKGLERROR
8928 }
8929
8930 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass, qboolean ui)
8931 {
8932         int i, j;
8933         texture_t *texture;
8934         R_FrameData_SetMark();
8935         // break the surface list down into batches by texture and use of lightmapping
8936         for (i = 0;i < numsurfaces;i = j)
8937         {
8938                 j = i + 1;
8939                 // texture is the base texture pointer, rsurface.texture is the
8940                 // current frame/skin the texture is directing us to use (for example
8941                 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
8942                 // use skin 1 instead)
8943                 texture = surfacelist[i]->texture;
8944                 rsurface.texture = R_GetCurrentTexture(texture);
8945                 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
8946                 {
8947                         // if this texture is not the kind we want, skip ahead to the next one
8948                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
8949                                 ;
8950                         continue;
8951                 }
8952                 if(depthonly || prepass)
8953                 {
8954                         rsurface.lightmaptexture = NULL;
8955                         rsurface.deluxemaptexture = NULL;
8956                         rsurface.uselightmaptexture = false;
8957                         // simply scan ahead until we find a different texture or lightmap state
8958                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
8959                                 ;
8960                 }
8961                 else
8962                 {
8963                         rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
8964                         rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
8965                         rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
8966                         // simply scan ahead until we find a different texture or lightmap state
8967                         for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
8968                                 ;
8969                 }
8970                 // render the range of surfaces
8971                 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass, ui);
8972         }
8973         R_FrameData_ReturnToMark();
8974 }
8975
8976 float locboxvertex3f[6*4*3] =
8977 {
8978         1,0,1, 1,0,0, 1,1,0, 1,1,1,
8979         0,1,1, 0,1,0, 0,0,0, 0,0,1,
8980         1,1,1, 1,1,0, 0,1,0, 0,1,1,
8981         0,0,1, 0,0,0, 1,0,0, 1,0,1,
8982         0,0,1, 1,0,1, 1,1,1, 0,1,1,
8983         1,0,0, 0,0,0, 0,1,0, 1,1,0
8984 };
8985
8986 unsigned short locboxelements[6*2*3] =
8987 {
8988          0, 1, 2, 0, 2, 3,
8989          4, 5, 6, 4, 6, 7,
8990          8, 9,10, 8,10,11,
8991         12,13,14, 12,14,15,
8992         16,17,18, 16,18,19,
8993         20,21,22, 20,22,23
8994 };
8995
8996 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
8997 {
8998         int i, j;
8999         cl_locnode_t *loc = (cl_locnode_t *)ent;
9000         vec3_t mins, size;
9001         float vertex3f[6*4*3];
9002         CHECKGLERROR
9003         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9004         GL_DepthMask(false);
9005         GL_DepthRange(0, 1);
9006         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9007         GL_DepthTest(true);
9008         GL_CullFace(GL_NONE);
9009         R_EntityMatrix(&identitymatrix);
9010
9011 //      R_Mesh_ResetTextureState();
9012
9013         i = surfacelist[0];
9014         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9015                          ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9016                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9017                         surfacelist[0] < 0 ? 0.5f : 0.125f);
9018
9019         if (VectorCompare(loc->mins, loc->maxs))
9020         {
9021                 VectorSet(size, 2, 2, 2);
9022                 VectorMA(loc->mins, -0.5f, size, mins);
9023         }
9024         else
9025         {
9026                 VectorCopy(loc->mins, mins);
9027                 VectorSubtract(loc->maxs, loc->mins, size);
9028         }
9029
9030         for (i = 0;i < 6*4*3;)
9031                 for (j = 0;j < 3;j++, i++)
9032                         vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9033
9034         R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9035         R_SetupShader_Generic_NoTexture(false, false);
9036         R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9037 }
9038
9039 void R_DrawLocs(void)
9040 {
9041         int index;
9042         cl_locnode_t *loc, *nearestloc;
9043         vec3_t center;
9044         nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9045         for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9046         {
9047                 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9048                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9049         }
9050 }
9051
9052 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9053 {
9054         if (decalsystem->decals)
9055                 Mem_Free(decalsystem->decals);
9056         memset(decalsystem, 0, sizeof(*decalsystem));
9057 }
9058
9059 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)
9060 {
9061         tridecal_t *decal;
9062         tridecal_t *decals;
9063         int i;
9064
9065         // expand or initialize the system
9066         if (decalsystem->maxdecals <= decalsystem->numdecals)
9067         {
9068                 decalsystem_t old = *decalsystem;
9069                 qboolean useshortelements;
9070                 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9071                 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9072                 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)));
9073                 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9074                 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9075                 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9076                 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9077                 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9078                 if (decalsystem->numdecals)
9079                         memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9080                 if (old.decals)
9081                         Mem_Free(old.decals);
9082                 for (i = 0;i < decalsystem->maxdecals*3;i++)
9083                         decalsystem->element3i[i] = i;
9084                 if (useshortelements)
9085                         for (i = 0;i < decalsystem->maxdecals*3;i++)
9086                                 decalsystem->element3s[i] = i;
9087         }
9088
9089         // grab a decal and search for another free slot for the next one
9090         decals = decalsystem->decals;
9091         decal = decalsystem->decals + (i = decalsystem->freedecal++);
9092         for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9093                 ;
9094         decalsystem->freedecal = i;
9095         if (decalsystem->numdecals <= i)
9096                 decalsystem->numdecals = i + 1;
9097
9098         // initialize the decal
9099         decal->lived = 0;
9100         decal->triangleindex = triangleindex;
9101         decal->surfaceindex = surfaceindex;
9102         decal->decalsequence = decalsequence;
9103         decal->color4f[0][0] = c0[0];
9104         decal->color4f[0][1] = c0[1];
9105         decal->color4f[0][2] = c0[2];
9106         decal->color4f[0][3] = 1;
9107         decal->color4f[1][0] = c1[0];
9108         decal->color4f[1][1] = c1[1];
9109         decal->color4f[1][2] = c1[2];
9110         decal->color4f[1][3] = 1;
9111         decal->color4f[2][0] = c2[0];
9112         decal->color4f[2][1] = c2[1];
9113         decal->color4f[2][2] = c2[2];
9114         decal->color4f[2][3] = 1;
9115         decal->vertex3f[0][0] = v0[0];
9116         decal->vertex3f[0][1] = v0[1];
9117         decal->vertex3f[0][2] = v0[2];
9118         decal->vertex3f[1][0] = v1[0];
9119         decal->vertex3f[1][1] = v1[1];
9120         decal->vertex3f[1][2] = v1[2];
9121         decal->vertex3f[2][0] = v2[0];
9122         decal->vertex3f[2][1] = v2[1];
9123         decal->vertex3f[2][2] = v2[2];
9124         decal->texcoord2f[0][0] = t0[0];
9125         decal->texcoord2f[0][1] = t0[1];
9126         decal->texcoord2f[1][0] = t1[0];
9127         decal->texcoord2f[1][1] = t1[1];
9128         decal->texcoord2f[2][0] = t2[0];
9129         decal->texcoord2f[2][1] = t2[1];
9130         TriangleNormal(v0, v1, v2, decal->plane);
9131         VectorNormalize(decal->plane);
9132         decal->plane[3] = DotProduct(v0, decal->plane);
9133 }
9134
9135 extern cvar_t cl_decals_bias;
9136 extern cvar_t cl_decals_models;
9137 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9138 // baseparms, parms, temps
9139 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)
9140 {
9141         int cornerindex;
9142         int index;
9143         float v[9][3];
9144         const float *vertex3f;
9145         const float *normal3f;
9146         int numpoints;
9147         float points[2][9][3];
9148         float temp[3];
9149         float tc[9][2];
9150         float f;
9151         float c[9][4];
9152         const int *e;
9153
9154         e = rsurface.modelelement3i + 3*triangleindex;
9155
9156         vertex3f = rsurface.modelvertex3f;
9157         normal3f = rsurface.modelnormal3f;
9158
9159         if (normal3f)
9160         {
9161                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9162                 {
9163                         index = 3*e[cornerindex];
9164                         VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9165                 }
9166         }
9167         else
9168         {
9169                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9170                 {
9171                         index = 3*e[cornerindex];
9172                         VectorCopy(vertex3f + index, v[cornerindex]);
9173                 }
9174         }
9175
9176         // cull backfaces
9177         //TriangleNormal(v[0], v[1], v[2], normal);
9178         //if (DotProduct(normal, localnormal) < 0.0f)
9179         //      continue;
9180         // clip by each of the box planes formed from the projection matrix
9181         // if anything survives, we emit the decal
9182         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]);
9183         if (numpoints < 3)
9184                 return;
9185         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]);
9186         if (numpoints < 3)
9187                 return;
9188         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]);
9189         if (numpoints < 3)
9190                 return;
9191         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]);
9192         if (numpoints < 3)
9193                 return;
9194         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]);
9195         if (numpoints < 3)
9196                 return;
9197         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]);
9198         if (numpoints < 3)
9199                 return;
9200         // some part of the triangle survived, so we have to accept it...
9201         if (dynamic)
9202         {
9203                 // dynamic always uses the original triangle
9204                 numpoints = 3;
9205                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9206                 {
9207                         index = 3*e[cornerindex];
9208                         VectorCopy(vertex3f + index, v[cornerindex]);
9209                 }
9210         }
9211         for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9212         {
9213                 // convert vertex positions to texcoords
9214                 Matrix4x4_Transform(projection, v[cornerindex], temp);
9215                 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9216                 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9217                 // calculate distance fade from the projection origin
9218                 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9219                 f = bound(0.0f, f, 1.0f);
9220                 c[cornerindex][0] = r * f;
9221                 c[cornerindex][1] = g * f;
9222                 c[cornerindex][2] = b * f;
9223                 c[cornerindex][3] = 1.0f;
9224                 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9225         }
9226         if (dynamic)
9227                 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);
9228         else
9229                 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9230                         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);
9231 }
9232 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)
9233 {
9234         matrix4x4_t projection;
9235         decalsystem_t *decalsystem;
9236         qboolean dynamic;
9237         dp_model_t *model;
9238         const msurface_t *surface;
9239         const msurface_t *surfaces;
9240         const int *surfacelist;
9241         const texture_t *texture;
9242         int numtriangles;
9243         int numsurfacelist;
9244         int surfacelistindex;
9245         int surfaceindex;
9246         int triangleindex;
9247         float localorigin[3];
9248         float localnormal[3];
9249         float localmins[3];
9250         float localmaxs[3];
9251         float localsize;
9252         //float normal[3];
9253         float planes[6][4];
9254         float angles[3];
9255         bih_t *bih;
9256         int bih_triangles_count;
9257         int bih_triangles[256];
9258         int bih_surfaces[256];
9259
9260         decalsystem = &ent->decalsystem;
9261         model = ent->model;
9262         if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9263         {
9264                 R_DecalSystem_Reset(&ent->decalsystem);
9265                 return;
9266         }
9267
9268         if (!model->brush.data_leafs && !cl_decals_models.integer)
9269         {
9270                 if (decalsystem->model)
9271                         R_DecalSystem_Reset(decalsystem);
9272                 return;
9273         }
9274
9275         if (decalsystem->model != model)
9276                 R_DecalSystem_Reset(decalsystem);
9277         decalsystem->model = model;
9278
9279         RSurf_ActiveModelEntity(ent, true, false, false);
9280
9281         Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9282         Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9283         VectorNormalize(localnormal);
9284         localsize = worldsize*rsurface.inversematrixscale;
9285         localmins[0] = localorigin[0] - localsize;
9286         localmins[1] = localorigin[1] - localsize;
9287         localmins[2] = localorigin[2] - localsize;
9288         localmaxs[0] = localorigin[0] + localsize;
9289         localmaxs[1] = localorigin[1] + localsize;
9290         localmaxs[2] = localorigin[2] + localsize;
9291
9292         //VectorCopy(localnormal, planes[4]);
9293         //VectorVectors(planes[4], planes[2], planes[0]);
9294         AnglesFromVectors(angles, localnormal, NULL, false);
9295         AngleVectors(angles, planes[0], planes[2], planes[4]);
9296         VectorNegate(planes[0], planes[1]);
9297         VectorNegate(planes[2], planes[3]);
9298         VectorNegate(planes[4], planes[5]);
9299         planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9300         planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9301         planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9302         planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9303         planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9304         planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9305
9306 #if 1
9307 // works
9308 {
9309         matrix4x4_t forwardprojection;
9310         Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9311         Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9312 }
9313 #else
9314 // broken
9315 {
9316         float projectionvector[4][3];
9317         VectorScale(planes[0], ilocalsize, projectionvector[0]);
9318         VectorScale(planes[2], ilocalsize, projectionvector[1]);
9319         VectorScale(planes[4], ilocalsize, projectionvector[2]);
9320         projectionvector[0][0] = planes[0][0] * ilocalsize;
9321         projectionvector[0][1] = planes[1][0] * ilocalsize;
9322         projectionvector[0][2] = planes[2][0] * ilocalsize;
9323         projectionvector[1][0] = planes[0][1] * ilocalsize;
9324         projectionvector[1][1] = planes[1][1] * ilocalsize;
9325         projectionvector[1][2] = planes[2][1] * ilocalsize;
9326         projectionvector[2][0] = planes[0][2] * ilocalsize;
9327         projectionvector[2][1] = planes[1][2] * ilocalsize;
9328         projectionvector[2][2] = planes[2][2] * ilocalsize;
9329         projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9330         projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9331         projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9332         Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9333 }
9334 #endif
9335
9336         dynamic = model->surfmesh.isanimated;
9337         numsurfacelist = model->nummodelsurfaces;
9338         surfacelist = model->sortedmodelsurfaces;
9339         surfaces = model->data_surfaces;
9340
9341         bih = NULL;
9342         bih_triangles_count = -1;
9343         if(!dynamic)
9344         {
9345                 if(model->render_bih.numleafs)
9346                         bih = &model->render_bih;
9347                 else if(model->collision_bih.numleafs)
9348                         bih = &model->collision_bih;
9349         }
9350         if(bih)
9351                 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9352         if(bih_triangles_count == 0)
9353                 return;
9354         if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9355                 return;
9356         if(bih_triangles_count > 0)
9357         {
9358                 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9359                 {
9360                         surfaceindex = bih_surfaces[triangleindex];
9361                         surface = surfaces + surfaceindex;
9362                         texture = surface->texture;
9363                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9364                                 continue;
9365                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9366                                 continue;
9367                         R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9368                 }
9369         }
9370         else
9371         {
9372                 for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
9373                 {
9374                         surfaceindex = surfacelist[surfacelistindex];
9375                         surface = surfaces + surfaceindex;
9376                         // check cull box first because it rejects more than any other check
9377                         if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9378                                 continue;
9379                         // skip transparent surfaces
9380                         texture = surface->texture;
9381                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9382                                 continue;
9383                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9384                                 continue;
9385                         numtriangles = surface->num_triangles;
9386                         for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9387                                 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9388                 }
9389         }
9390 }
9391
9392 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9393 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)
9394 {
9395         int renderentityindex;
9396         float worldmins[3];
9397         float worldmaxs[3];
9398         entity_render_t *ent;
9399
9400         worldmins[0] = worldorigin[0] - worldsize;
9401         worldmins[1] = worldorigin[1] - worldsize;
9402         worldmins[2] = worldorigin[2] - worldsize;
9403         worldmaxs[0] = worldorigin[0] + worldsize;
9404         worldmaxs[1] = worldorigin[1] + worldsize;
9405         worldmaxs[2] = worldorigin[2] + worldsize;
9406
9407         R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9408
9409         for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9410         {
9411                 ent = r_refdef.scene.entities[renderentityindex];
9412                 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9413                         continue;
9414
9415                 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9416         }
9417 }
9418
9419 typedef struct r_decalsystem_splatqueue_s
9420 {
9421         vec3_t worldorigin;
9422         vec3_t worldnormal;
9423         float color[4];
9424         float tcrange[4];
9425         float worldsize;
9426         unsigned int decalsequence;
9427 }
9428 r_decalsystem_splatqueue_t;
9429
9430 int r_decalsystem_numqueued = 0;
9431 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9432
9433 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)
9434 {
9435         r_decalsystem_splatqueue_t *queue;
9436
9437         if (r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9438                 return;
9439
9440         queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9441         VectorCopy(worldorigin, queue->worldorigin);
9442         VectorCopy(worldnormal, queue->worldnormal);
9443         Vector4Set(queue->color, r, g, b, a);
9444         Vector4Set(queue->tcrange, s1, t1, s2, t2);
9445         queue->worldsize = worldsize;
9446         queue->decalsequence = cl.decalsequence++;
9447 }
9448
9449 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9450 {
9451         int i;
9452         r_decalsystem_splatqueue_t *queue;
9453
9454         for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9455                 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);
9456         r_decalsystem_numqueued = 0;
9457 }
9458
9459 extern cvar_t cl_decals_max;
9460 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9461 {
9462         int i;
9463         decalsystem_t *decalsystem = &ent->decalsystem;
9464         int numdecals;
9465         unsigned int killsequence;
9466         tridecal_t *decal;
9467         float frametime;
9468         float lifetime;
9469
9470         if (!decalsystem->numdecals)
9471                 return;
9472
9473         if (r_showsurfaces.integer)
9474                 return;
9475
9476         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9477         {
9478                 R_DecalSystem_Reset(decalsystem);
9479                 return;
9480         }
9481
9482         killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9483         lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9484
9485         if (decalsystem->lastupdatetime)
9486                 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9487         else
9488                 frametime = 0;
9489         decalsystem->lastupdatetime = r_refdef.scene.time;
9490         numdecals = decalsystem->numdecals;
9491
9492         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9493         {
9494                 if (decal->color4f[0][3])
9495                 {
9496                         decal->lived += frametime;
9497                         if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9498                         {
9499                                 memset(decal, 0, sizeof(*decal));
9500                                 if (decalsystem->freedecal > i)
9501                                         decalsystem->freedecal = i;
9502                         }
9503                 }
9504         }
9505         decal = decalsystem->decals;
9506         while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9507                 numdecals--;
9508
9509         // collapse the array by shuffling the tail decals into the gaps
9510         for (;;)
9511         {
9512                 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
9513                         decalsystem->freedecal++;
9514                 if (decalsystem->freedecal == numdecals)
9515                         break;
9516                 decal[decalsystem->freedecal] = decal[--numdecals];
9517         }
9518
9519         decalsystem->numdecals = numdecals;
9520
9521         if (numdecals <= 0)
9522         {
9523                 // if there are no decals left, reset decalsystem
9524                 R_DecalSystem_Reset(decalsystem);
9525         }
9526 }
9527
9528 extern skinframe_t *decalskinframe;
9529 static void R_DrawModelDecals_Entity(entity_render_t *ent)
9530 {
9531         int i;
9532         decalsystem_t *decalsystem = &ent->decalsystem;
9533         int numdecals;
9534         tridecal_t *decal;
9535         float faderate;
9536         float alpha;
9537         float *v3f;
9538         float *c4f;
9539         float *t2f;
9540         const int *e;
9541         const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
9542         int numtris = 0;
9543
9544         numdecals = decalsystem->numdecals;
9545         if (!numdecals)
9546                 return;
9547
9548         if (r_showsurfaces.integer)
9549                 return;
9550
9551         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9552         {
9553                 R_DecalSystem_Reset(decalsystem);
9554                 return;
9555         }
9556
9557         // if the model is static it doesn't matter what value we give for
9558         // wantnormals and wanttangents, so this logic uses only rules applicable
9559         // to a model, knowing that they are meaningless otherwise
9560         RSurf_ActiveModelEntity(ent, false, false, false);
9561
9562         decalsystem->lastupdatetime = r_refdef.scene.time;
9563
9564         faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
9565
9566         // update vertex positions for animated models
9567         v3f = decalsystem->vertex3f;
9568         c4f = decalsystem->color4f;
9569         t2f = decalsystem->texcoord2f;
9570         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9571         {
9572                 if (!decal->color4f[0][3])
9573                         continue;
9574
9575                 if (surfacevisible && !surfacevisible[decal->surfaceindex])
9576                         continue;
9577
9578                 // skip backfaces
9579                 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
9580                         continue;
9581
9582                 // update color values for fading decals
9583                 if (decal->lived >= cl_decals_time.value)
9584                         alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
9585                 else
9586                         alpha = 1.0f;
9587
9588                 c4f[ 0] = decal->color4f[0][0] * alpha;
9589                 c4f[ 1] = decal->color4f[0][1] * alpha;
9590                 c4f[ 2] = decal->color4f[0][2] * alpha;
9591                 c4f[ 3] = 1;
9592                 c4f[ 4] = decal->color4f[1][0] * alpha;
9593                 c4f[ 5] = decal->color4f[1][1] * alpha;
9594                 c4f[ 6] = decal->color4f[1][2] * alpha;
9595                 c4f[ 7] = 1;
9596                 c4f[ 8] = decal->color4f[2][0] * alpha;
9597                 c4f[ 9] = decal->color4f[2][1] * alpha;
9598                 c4f[10] = decal->color4f[2][2] * alpha;
9599                 c4f[11] = 1;
9600
9601                 t2f[0] = decal->texcoord2f[0][0];
9602                 t2f[1] = decal->texcoord2f[0][1];
9603                 t2f[2] = decal->texcoord2f[1][0];
9604                 t2f[3] = decal->texcoord2f[1][1];
9605                 t2f[4] = decal->texcoord2f[2][0];
9606                 t2f[5] = decal->texcoord2f[2][1];
9607
9608                 // update vertex positions for animated models
9609                 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
9610                 {
9611                         e = rsurface.modelelement3i + 3*decal->triangleindex;
9612                         VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
9613                         VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
9614                         VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
9615                 }
9616                 else
9617                 {
9618                         VectorCopy(decal->vertex3f[0], v3f);
9619                         VectorCopy(decal->vertex3f[1], v3f + 3);
9620                         VectorCopy(decal->vertex3f[2], v3f + 6);
9621                 }
9622
9623                 if (r_refdef.fogenabled)
9624                 {
9625                         alpha = RSurf_FogVertex(v3f);
9626                         VectorScale(c4f, alpha, c4f);
9627                         alpha = RSurf_FogVertex(v3f + 3);
9628                         VectorScale(c4f + 4, alpha, c4f + 4);
9629                         alpha = RSurf_FogVertex(v3f + 6);
9630                         VectorScale(c4f + 8, alpha, c4f + 8);
9631                 }
9632
9633                 v3f += 9;
9634                 c4f += 12;
9635                 t2f += 6;
9636                 numtris++;
9637         }
9638
9639         if (numtris > 0)
9640         {
9641                 r_refdef.stats[r_stat_drawndecals] += numtris;
9642
9643                 // now render the decals all at once
9644                 // (this assumes they all use one particle font texture!)
9645                 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);
9646 //              R_Mesh_ResetTextureState();
9647                 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
9648                 GL_DepthMask(false);
9649                 GL_DepthRange(0, 1);
9650                 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
9651                 GL_DepthTest(true);
9652                 GL_CullFace(GL_NONE);
9653                 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
9654                 R_SetupShader_Generic(decalskinframe->base, false, false, false);
9655                 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
9656         }
9657 }
9658
9659 static void R_DrawModelDecals(void)
9660 {
9661         int i, numdecals;
9662
9663         // fade faster when there are too many decals
9664         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9665         for (i = 0;i < r_refdef.scene.numentities;i++)
9666                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9667
9668         R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
9669         for (i = 0;i < r_refdef.scene.numentities;i++)
9670                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9671                         R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
9672
9673         R_DecalSystem_ApplySplatEntitiesQueue();
9674
9675         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9676         for (i = 0;i < r_refdef.scene.numentities;i++)
9677                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9678
9679         r_refdef.stats[r_stat_totaldecals] += numdecals;
9680
9681         if (r_showsurfaces.integer || !r_drawdecals.integer)
9682                 return;
9683
9684         R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
9685
9686         for (i = 0;i < r_refdef.scene.numentities;i++)
9687         {
9688                 if (!r_refdef.viewcache.entityvisible[i])
9689                         continue;
9690                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9691                         R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
9692         }
9693 }
9694
9695 extern cvar_t mod_collision_bih;
9696 static void R_DrawDebugModel(void)
9697 {
9698         entity_render_t *ent = rsurface.entity;
9699         int i, j, flagsmask;
9700         const msurface_t *surface;
9701         dp_model_t *model = ent->model;
9702
9703         if (!sv.active  && !cls.demoplayback && ent != r_refdef.scene.worldentity)
9704                 return;
9705
9706         if (r_showoverdraw.value > 0)
9707         {
9708                 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
9709                 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9710                 R_SetupShader_Generic_NoTexture(false, false);
9711                 GL_DepthTest(false);
9712                 GL_DepthMask(false);
9713                 GL_DepthRange(0, 1);
9714                 GL_BlendFunc(GL_ONE, GL_ONE);
9715                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9716                 {
9717                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9718                                 continue;
9719                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9720                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9721                         {
9722                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
9723                                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
9724                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9725                                         GL_Color(c, 0, 0, 1.0f);
9726                                 else if (ent == r_refdef.scene.worldentity)
9727                                         GL_Color(c, c, c, 1.0f);
9728                                 else
9729                                         GL_Color(0, c, 0, 1.0f);
9730                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9731                                 RSurf_DrawBatch();
9732                         }
9733                 }
9734                 rsurface.texture = NULL;
9735         }
9736
9737         flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9738
9739 //      R_Mesh_ResetTextureState();
9740         R_SetupShader_Generic_NoTexture(false, false);
9741         GL_DepthRange(0, 1);
9742         GL_DepthTest(!r_showdisabledepthtest.integer);
9743         GL_DepthMask(false);
9744         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9745
9746         if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
9747         {
9748                 int triangleindex;
9749                 int bihleafindex;
9750                 qboolean cullbox = false;
9751                 const q3mbrush_t *brush;
9752                 const bih_t *bih = &model->collision_bih;
9753                 const bih_leaf_t *bihleaf;
9754                 float vertex3f[3][3];
9755                 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
9756                 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
9757                 {
9758                         if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
9759                                 continue;
9760                         switch (bihleaf->type)
9761                         {
9762                         case BIH_BRUSH:
9763                                 brush = model->brush.data_brushes + bihleaf->itemindex;
9764                                 if (brush->colbrushf && brush->colbrushf->numtriangles)
9765                                 {
9766                                         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);
9767                                         R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
9768                                         R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
9769                                 }
9770                                 break;
9771                         case BIH_COLLISIONTRIANGLE:
9772                                 triangleindex = bihleaf->itemindex;
9773                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
9774                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
9775                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
9776                                 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);
9777                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9778                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9779                                 break;
9780                         case BIH_RENDERTRIANGLE:
9781                                 triangleindex = bihleaf->itemindex;
9782                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
9783                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
9784                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
9785                                 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);
9786                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9787                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9788                                 break;
9789                         }
9790                 }
9791         }
9792
9793         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9794
9795 #ifndef USE_GLES2
9796         if (r_showtris.value > 0 && qglPolygonMode)
9797         {
9798                 if (r_showdisabledepthtest.integer)
9799                 {
9800                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9801                         GL_DepthMask(false);
9802                 }
9803                 else
9804                 {
9805                         GL_BlendFunc(GL_ONE, GL_ZERO);
9806                         GL_DepthMask(true);
9807                 }
9808                 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
9809                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9810                 {
9811                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9812                                 continue;
9813                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9814                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9815                         {
9816                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9817                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9818                                         GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
9819                                 else if (ent == r_refdef.scene.worldentity)
9820                                         GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
9821                                 else
9822                                         GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
9823                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9824                                 RSurf_DrawBatch();
9825                         }
9826                 }
9827                 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
9828                 rsurface.texture = NULL;
9829         }
9830
9831 # if 0
9832         // FIXME!  implement r_shownormals with just triangles
9833         if (r_shownormals.value != 0 && qglBegin)
9834         {
9835                 int l, k;
9836                 vec3_t v;
9837                 if (r_showdisabledepthtest.integer)
9838                 {
9839                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9840                         GL_DepthMask(false);
9841                 }
9842                 else
9843                 {
9844                         GL_BlendFunc(GL_ONE, GL_ZERO);
9845                         GL_DepthMask(true);
9846                 }
9847                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9848                 {
9849                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9850                                 continue;
9851                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9852                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9853                         {
9854                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9855                                 qglBegin(GL_LINES);
9856                                 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
9857                                 {
9858                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9859                                         {
9860                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9861                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9862                                                 qglVertex3f(v[0], v[1], v[2]);
9863                                                 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9864                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9865                                                 qglVertex3f(v[0], v[1], v[2]);
9866                                         }
9867                                 }
9868                                 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
9869                                 {
9870                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9871                                         {
9872                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9873                                                 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
9874                                                 qglVertex3f(v[0], v[1], v[2]);
9875                                                 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
9876                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9877                                                 qglVertex3f(v[0], v[1], v[2]);
9878                                         }
9879                                 }
9880                                 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
9881                                 {
9882                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9883                                         {
9884                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9885                                                 GL_Color(0, r_refdef.view.colorscale, 0, 1);
9886                                                 qglVertex3f(v[0], v[1], v[2]);
9887                                                 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
9888                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9889                                                 qglVertex3f(v[0], v[1], v[2]);
9890                                         }
9891                                 }
9892                                 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
9893                                 {
9894                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9895                                         {
9896                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9897                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9898                                                 qglVertex3f(v[0], v[1], v[2]);
9899                                                 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9900                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9901                                                 qglVertex3f(v[0], v[1], v[2]);
9902                                         }
9903                                 }
9904                                 qglEnd();
9905                                 CHECKGLERROR
9906                         }
9907                 }
9908                 rsurface.texture = NULL;
9909         }
9910 # endif
9911 #endif
9912 }
9913
9914 int r_maxsurfacelist = 0;
9915 const msurface_t **r_surfacelist = NULL;
9916 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass, qboolean ui)
9917 {
9918         int i, j, endj, flagsmask;
9919         dp_model_t *model = ent->model;
9920         msurface_t *surfaces;
9921         unsigned char *update;
9922         int numsurfacelist = 0;
9923         if (model == NULL)
9924                 return;
9925
9926         if (r_maxsurfacelist < model->num_surfaces)
9927         {
9928                 r_maxsurfacelist = model->num_surfaces;
9929                 if (r_surfacelist)
9930                         Mem_Free((msurface_t **)r_surfacelist);
9931                 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
9932         }
9933
9934         if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
9935                 RSurf_ActiveModelEntity(ent, false, false, false);
9936         else if (prepass)
9937                 RSurf_ActiveModelEntity(ent, true, true, true);
9938         else if (depthonly)
9939                 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
9940         else
9941                 RSurf_ActiveModelEntity(ent, true, true, false);
9942
9943         surfaces = model->data_surfaces;
9944         update = model->brushq1.lightmapupdateflags;
9945
9946         // update light styles
9947         if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0)
9948         {
9949                 model_brush_lightstyleinfo_t *style;
9950                 for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
9951                 {
9952                         if (style->value != r_refdef.scene.lightstylevalue[style->style])
9953                         {
9954                                 int *list = style->surfacelist;
9955                                 style->value = r_refdef.scene.lightstylevalue[style->style];
9956                                 for (j = 0;j < style->numsurfaces;j++)
9957                                         update[list[j]] = true;
9958                         }
9959                 }
9960         }
9961
9962         flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
9963
9964         if (debug)
9965         {
9966                 R_DrawDebugModel();
9967                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
9968                 return;
9969         }
9970
9971         rsurface.lightmaptexture = NULL;
9972         rsurface.deluxemaptexture = NULL;
9973         rsurface.uselightmaptexture = false;
9974         rsurface.texture = NULL;
9975         rsurface.rtlight = NULL;
9976         numsurfacelist = 0;
9977         // add visible surfaces to draw list
9978         if (ent == r_refdef.scene.worldentity)
9979         {
9980                 // for the world entity, check surfacevisible
9981                 for (i = 0;i < model->nummodelsurfaces;i++)
9982                 {
9983                         j = model->sortedmodelsurfaces[i];
9984                         if (r_refdef.viewcache.world_surfacevisible[j])
9985                                 r_surfacelist[numsurfacelist++] = surfaces + j;
9986                 }
9987         }
9988         else if (ui)
9989         {
9990                 // for ui we have to preserve the order of surfaces
9991                 for (i = 0; i < model->nummodelsurfaces; i++)
9992                         r_surfacelist[numsurfacelist++] = surfaces + model->firstmodelsurface + i;
9993         }
9994         else
9995         {
9996                 // add all surfaces
9997                 for (i = 0; i < model->nummodelsurfaces; i++)
9998                         r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
9999         }
10000         // don't do anything if there were no surfaces
10001         if (!numsurfacelist)
10002         {
10003                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10004                 return;
10005         }
10006         // update lightmaps if needed
10007         if (update)
10008         {
10009                 int updated = 0;
10010                 for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
10011                 {
10012                         if (update[j])
10013                         {
10014                                 updated++;
10015                                 R_BuildLightMap(ent, surfaces + j);
10016                         }
10017                 }
10018         }
10019
10020         R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass, ui);
10021
10022         // add to stats if desired
10023         if (r_speeds.integer && !skysurfaces && !depthonly)
10024         {
10025                 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10026                 for (j = 0;j < numsurfacelist;j++)
10027                         r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10028         }
10029
10030         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10031 }
10032
10033 void R_DebugLine(vec3_t start, vec3_t end)
10034 {
10035         dp_model_t *mod = CL_Mesh_UI();
10036         msurface_t *surf;
10037         int e0, e1, e2, e3;
10038         float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10039         float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10040         float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10041         vec4_t w[2], s[2];
10042
10043         // transform to screen coords first
10044         Vector4Set(w[0], start[0], start[1], start[2], 1);
10045         Vector4Set(w[1], end[0], end[1], end[2], 1);
10046         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10047         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10048         x1 = s[0][0] * vid_conwidth.value / vid.width;
10049         y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10050         x2 = s[1][0] * vid_conwidth.value / vid.width;
10051         y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10052         //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10053
10054         // add the line to the UI mesh for drawing later
10055
10056         // width is measured in real pixels
10057         if (fabs(x2 - x1) > fabs(y2 - y1))
10058         {
10059                 offsetx = 0;
10060                 offsety = 0.5f * width * vid_conheight.value / vid.height;
10061         }
10062         else
10063         {
10064                 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10065                 offsety = 0;
10066         }
10067         surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_WALL | MATERIALFLAG_VERTEXCOLOR | MATERIALFLAG_ALPHAGEN_VERTEX), true);
10068         e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10069         e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10070         e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10071         e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10072         Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10073         Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10074
10075 }
10076
10077
10078 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)
10079 {
10080         int q;
10081         static texture_t texture;
10082         static msurface_t surface;
10083         const msurface_t *surfacelist = &surface;
10084
10085         // fake enough texture and surface state to render this geometry
10086
10087         texture.update_lastrenderframe = -1; // regenerate this texture
10088         texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10089         texture.basealpha = 1.0f;
10090         texture.currentskinframe = skinframe;
10091         texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10092         texture.offsetmapping = OFFSETMAPPING_OFF;
10093         texture.offsetscale = 1;
10094         texture.specularscalemod = 1;
10095         texture.specularpowermod = 1;
10096         texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10097
10098         R_DrawCustomSurface_Texture(&texture, texmatrix, materialflags, firstvertex, numvertices, firsttriangle, numtriangles, writedepth, prepass, ui);
10099 }
10100
10101 void R_DrawCustomSurface_Texture(texture_t *texture, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass, qboolean ui)
10102 {
10103         static msurface_t surface;
10104         const msurface_t *surfacelist = &surface;
10105
10106         // fake enough texture and surface state to render this geometry
10107         surface.texture = texture;
10108         surface.num_triangles = numtriangles;
10109         surface.num_firsttriangle = firsttriangle;
10110         surface.num_vertices = numvertices;
10111         surface.num_firstvertex = firstvertex;
10112
10113         // now render it
10114         rsurface.texture = R_GetCurrentTexture(surface.texture);
10115         rsurface.lightmaptexture = NULL;
10116         rsurface.deluxemaptexture = NULL;
10117         rsurface.uselightmaptexture = false;
10118         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass, ui);
10119 }