2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
29 #include "cl_collision.h"
32 // Enable NVIDIA High Performance Graphics while using Integrated Graphics.
36 __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
42 mempool_t *r_main_mempool;
43 rtexturepool_t *r_main_texturepool;
45 static int r_textureframe = 0; ///< used only by R_GetCurrentTexture
47 static qboolean r_loadnormalmap;
48 static qboolean r_loadgloss;
50 static qboolean r_loaddds;
51 static qboolean r_savedds;
52 static qboolean r_gpuskeletal;
59 cvar_t r_motionblur = {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_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_SAVE, "r_motionblur_averaging", "0.1", "sliding average reaction time for velocity (higher = slower adaption to change)"};
62 cvar_t r_motionblur_randomize = {CVAR_SAVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"};
63 cvar_t r_motionblur_minblur = {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_SAVE, "r_motionblur_maxblur", "0.9", "maxmimum amount of blur"};
65 cvar_t r_motionblur_velocityfactor = {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_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_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_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_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_SAVE, "r_motionblur_mousefactor_maxspeed", "50", "upper value of mouse acceleration when it reaches the peak factor into blur equation"};
72 // TODO do we want a r_equalize_entities cvar that works on all ents, or would that be a cheat?
73 cvar_t r_equalize_entities_fullbright = {CVAR_SAVE, "r_equalize_entities_fullbright", "0", "render fullbright entities by equalizing their lightness, not by not rendering light (DEPRECATED)"};
74 cvar_t r_equalize_entities_minambient = {CVAR_SAVE, "r_equalize_entities_minambient", "0.5", "light equalizing: ensure at least this ambient/diffuse ratio (DEPRECATED)"};
75 cvar_t r_equalize_entities_by = {CVAR_SAVE, "r_equalize_entities_by", "0.7", "light equalizing: exponent of dynamics compression (0 = no compression, 1 = full compression) (DEPRECATED)"};
76 cvar_t r_equalize_entities_to = {CVAR_SAVE, "r_equalize_entities_to", "0.8", "light equalizing: target light level (DEPRECATED)"};
78 cvar_t r_depthfirst = {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"};
79 cvar_t r_useinfinitefarclip = {CVAR_SAVE, "r_useinfinitefarclip", "1", "enables use of a special kind of projection matrix that has an extremely large farclip"};
80 cvar_t r_farclip_base = {0, "r_farclip_base", "65536", "farclip (furthest visible distance) for rendering when r_useinfinitefarclip is 0"};
81 cvar_t r_farclip_world = {0, "r_farclip_world", "2", "adds map size to farclip multiplied by this value"};
82 cvar_t r_nearclip = {0, "r_nearclip", "1", "distance from camera of nearclip plane" };
83 cvar_t r_deformvertexes = {0, "r_deformvertexes", "1", "allows use of deformvertexes in shader files (can be turned off to check performance impact)"};
84 cvar_t r_transparent = {0, "r_transparent", "1", "allows use of transparent surfaces (can be turned off to check performance impact)"};
85 cvar_t r_transparent_alphatocoverage = {0, "r_transparent_alphatocoverage", "1", "enables GL_ALPHA_TO_COVERAGE antialiasing technique on alphablend and alphatest surfaces when using vid_samples 2 or higher"};
86 cvar_t r_transparent_sortsurfacesbynearest = {0, "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"};
87 cvar_t r_transparent_useplanardistance = {0, "r_transparent_useplanardistance", "0", "sort transparent meshes by distance from view plane rather than spherical distance to the chosen point"};
88 cvar_t r_showoverdraw = {0, "r_showoverdraw", "0", "shows overlapping geometry"};
89 cvar_t r_showbboxes = {0, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%, 10 = 100%)"};
90 cvar_t r_showbboxes_client = { 0, "r_showbboxes_client", "0", "shows bounding boxes of clientside qc entities, value controls opacity scaling (1 = 10%, 10 = 100%)" };
91 cvar_t r_showsurfaces = {0, "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)"};
92 cvar_t r_showtris = {0, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
93 cvar_t r_shownormals = {0, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
94 cvar_t r_showlighting = {0, "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"};
95 cvar_t r_showshadowvolumes = {0, "r_showshadowvolumes", "0", "shows areas shadowed by lights, useful for finding out why some areas of a map render slowly (bright blue = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
96 cvar_t r_showcollisionbrushes = {0, "r_showcollisionbrushes", "0", "draws collision brushes in quake3 maps (mode 1), mode 2 disables rendering of world (trippy!)"};
97 cvar_t r_showcollisionbrushes_polygonfactor = {0, "r_showcollisionbrushes_polygonfactor", "-1", "expands outward the brush polygons a little bit, used to make collision brushes appear infront of walls"};
98 cvar_t r_showcollisionbrushes_polygonoffset = {0, "r_showcollisionbrushes_polygonoffset", "0", "nudges brush polygon depth in hardware depth units, used to make collision brushes appear infront of walls"};
99 cvar_t r_showdisabledepthtest = {0, "r_showdisabledepthtest", "0", "disables depth testing on r_show* cvars, allowing you to see what hidden geometry the graphics card is processing"};
100 cvar_t r_showspriteedges = {0, "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"};
101 cvar_t r_showparticleedges = {0, "r_showparticleedges", "0", "renders a debug outline to show the polygon shape of each particle, for debugging rendering bugs with specific view types"};
102 cvar_t r_drawportals = {0, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
103 cvar_t r_drawentities = {0, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
104 cvar_t r_draw2d = {0, "r_draw2d","1", "draw 2D stuff (dangerous to turn off)"};
105 cvar_t r_drawworld = {0, "r_drawworld","1", "draw world (most static stuff)"};
106 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1", "draw your weapon model"};
107 cvar_t r_drawexteriormodel = {0, "r_drawexteriormodel","1", "draw your player model (e.g. in chase cam, reflections)"};
108 cvar_t r_cullentities_trace = {0, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
109 cvar_t r_cullentities_trace_entityocclusion = { 0, "r_cullentities_trace_entityocclusion", "1", "check for occluding entities such as doors, not just world hull" };
110 cvar_t r_cullentities_trace_samples = {0, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling (in addition to center sample)"};
111 cvar_t r_cullentities_trace_tempentitysamples = {0, "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)"};
112 cvar_t r_cullentities_trace_enlarge = {0, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
113 cvar_t r_cullentities_trace_expand = {0, "r_cullentities_trace_expand", "0", "box expanded by this many units for entity culling"};
114 cvar_t r_cullentities_trace_pad = {0, "r_cullentities_trace_pad", "8", "accept traces that hit within this many units of the box"};
115 cvar_t r_cullentities_trace_delay = {0, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
116 cvar_t r_cullentities_trace_eyejitter = {0, "r_cullentities_trace_eyejitter", "16", "randomly offset rays from the eye by this much to reduce the odds of flickering"};
117 cvar_t r_sortentities = {0, "r_sortentities", "0", "sort entities before drawing (might be faster)"};
118 cvar_t r_speeds = {0, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
119 cvar_t r_fullbright = {0, "r_fullbright","0", "makes map very bright and renders faster"};
121 cvar_t r_fakelight = {0, "r_fakelight","0", "render 'fake' lighting instead of real lightmaps (DEPRECATED)"};
122 cvar_t r_fakelight_intensity = {0, "r_fakelight_intensity","0.75", "fakelight intensity modifier (DEPRECATED)"};
123 #define FAKELIGHT_ENABLED (r_fakelight.integer >= 2 || (r_fakelight.integer && r_refdef.scene.worldmodel && !r_refdef.scene.worldmodel->lit))
125 cvar_t r_fullbright_directed = {0, "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"};
126 cvar_t r_fullbright_directed_ambient = {0, "r_fullbright_directed_ambient", "0.5", "ambient light multiplier for directed fullbright"};
127 cvar_t r_fullbright_directed_diffuse = {0, "r_fullbright_directed_diffuse", "0.75", "diffuse light multiplier for directed fullbright"};
128 cvar_t r_fullbright_directed_pitch = {0, "r_fullbright_directed_pitch", "20", "constant pitch direction ('height') of the fake light source to use for fullbright"};
129 cvar_t r_fullbright_directed_pitch_relative = {0, "r_fullbright_directed_pitch_relative", "0", "whether r_fullbright_directed_pitch is interpreted as absolute (0) or relative (1) pitch"};
131 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1", "opacity of water polygons"};
132 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
133 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
134 cvar_t r_shadows = {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."};
135 cvar_t r_shadows_darken = {CVAR_SAVE, "r_shadows_darken", "0.5", "how much shadowed areas will be darkened"};
136 cvar_t r_shadows_throwdistance = {CVAR_SAVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
137 cvar_t r_shadows_throwdirection = {CVAR_SAVE, "r_shadows_throwdirection", "0 0 -1", "override throwing direction for r_shadows 2"};
138 cvar_t r_shadows_drawafterrtlighting = {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."};
139 cvar_t r_shadows_castfrombmodels = {CVAR_SAVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
140 cvar_t r_shadows_focus = {CVAR_SAVE, "r_shadows_focus", "0 0 0", "offset the shadowed area focus"};
141 cvar_t r_shadows_shadowmapscale = {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."};
142 cvar_t r_shadows_shadowmapbias = {CVAR_SAVE, "r_shadows_shadowmapbias", "-1", "sets shadowmap bias for fake shadows. -1 sets the value of r_shadow_shadowmapping_bias. Needs shadowmapping ON."};
143 cvar_t r_q1bsp_skymasking = {0, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
144 cvar_t r_polygonoffset_submodel_factor = {0, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
145 cvar_t r_polygonoffset_submodel_offset = {0, "r_polygonoffset_submodel_offset", "14", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
146 cvar_t r_polygonoffset_decals_factor = {0, "r_polygonoffset_decals_factor", "0", "biases depth values of decals to prevent z-fighting artifacts"};
147 cvar_t r_polygonoffset_decals_offset = {0, "r_polygonoffset_decals_offset", "-14", "biases depth values of decals to prevent z-fighting artifacts"};
148 cvar_t r_fog_exp2 = {0, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"};
149 cvar_t r_fog_clear = {0, "r_fog_clear", "1", "clears renderbuffer with fog color before render starts"};
150 cvar_t r_drawfog = {CVAR_SAVE, "r_drawfog", "1", "allows one to disable fog rendering"};
151 cvar_t r_transparentdepthmasking = {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"};
152 cvar_t r_transparent_sortmindist = {CVAR_SAVE, "r_transparent_sortmindist", "0", "lower distance limit for transparent sorting"};
153 cvar_t r_transparent_sortmaxdist = {CVAR_SAVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"};
154 cvar_t r_transparent_sortarraysize = {CVAR_SAVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"};
155 cvar_t r_celshading = {CVAR_SAVE, "r_celshading", "0", "cartoon-style light shading (OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9
156 cvar_t r_celoutlines = {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
158 cvar_t gl_fogenable = {0, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
159 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
160 cvar_t gl_fogred = {0, "gl_fogred","0.3", "nehahra fog color red value (for Nehahra compatibility only)"};
161 cvar_t gl_foggreen = {0, "gl_foggreen","0.3", "nehahra fog color green value (for Nehahra compatibility only)"};
162 cvar_t gl_fogblue = {0, "gl_fogblue","0.3", "nehahra fog color blue value (for Nehahra compatibility only)"};
163 cvar_t gl_fogstart = {0, "gl_fogstart", "0", "nehahra fog start distance (for Nehahra compatibility only)"};
164 cvar_t gl_fogend = {0, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
165 cvar_t gl_skyclip = {0, "gl_skyclip", "4608", "nehahra farclip distance - the real fog end (for Nehahra compatibility only)"};
167 cvar_t r_texture_dds_load = {CVAR_SAVE, "r_texture_dds_load", "0", "load compressed dds/filename.dds texture instead of filename.tga, if the file exists (requires driver support)"};
168 cvar_t r_texture_dds_save = {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"};
170 cvar_t r_textureunits = {0, "r_textureunits", "32", "number of texture units to use in GL 1.1 and GL 1.3 rendering paths"};
171 static cvar_t gl_combine = {CVAR_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"};
172 static cvar_t r_glsl = {CVAR_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"};
174 cvar_t r_usedepthtextures = {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"};
175 cvar_t r_viewfbo = {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"};
176 cvar_t r_rendertarget_debug = {0, "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)"};
177 cvar_t r_viewscale = {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"};
178 cvar_t r_viewscale_fpsscaling = {CVAR_SAVE, "r_viewscale_fpsscaling", "0", "change resolution based on framerate"};
179 cvar_t r_viewscale_fpsscaling_min = {CVAR_SAVE, "r_viewscale_fpsscaling_min", "0.0625", "worst acceptable quality"};
180 cvar_t r_viewscale_fpsscaling_multiply = {CVAR_SAVE, "r_viewscale_fpsscaling_multiply", "5", "adjust quality up or down by the frametime difference from 1.0/target, multiplied by this factor"};
181 cvar_t r_viewscale_fpsscaling_stepsize = {CVAR_SAVE, "r_viewscale_fpsscaling_stepsize", "0.01", "smallest adjustment to hit the target framerate (this value prevents minute oscillations)"};
182 cvar_t r_viewscale_fpsscaling_stepmax = {CVAR_SAVE, "r_viewscale_fpsscaling_stepmax", "1.00", "largest adjustment to hit the target framerate (this value prevents wild overshooting of the estimate)"};
183 cvar_t r_viewscale_fpsscaling_target = {CVAR_SAVE, "r_viewscale_fpsscaling_target", "70", "desired framerate"};
185 cvar_t r_glsl_skeletal = {CVAR_SAVE, "r_glsl_skeletal", "1", "render skeletal models faster using a gpu-skinning technique"};
186 cvar_t r_glsl_deluxemapping = {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)"};
187 cvar_t r_glsl_offsetmapping = {CVAR_SAVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
188 cvar_t r_glsl_offsetmapping_steps = {CVAR_SAVE, "r_glsl_offsetmapping_steps", "2", "offset mapping steps (note: too high values may be not supported by your GPU)"};
189 cvar_t r_glsl_offsetmapping_reliefmapping = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
190 cvar_t r_glsl_offsetmapping_reliefmapping_steps = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_steps", "10", "relief mapping steps (note: too high values may be not supported by your GPU)"};
191 cvar_t r_glsl_offsetmapping_reliefmapping_refinesteps = {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)"};
192 cvar_t r_glsl_offsetmapping_scale = {CVAR_SAVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
193 cvar_t r_glsl_offsetmapping_lod = {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"};
194 cvar_t r_glsl_offsetmapping_lod_distance = {CVAR_SAVE, "r_glsl_offsetmapping_lod_distance", "32", "first LOD level distance, second level (-50% steps) is 2x of this, third (33%) - 3x etc."};
195 cvar_t r_glsl_postprocess = {CVAR_SAVE, "r_glsl_postprocess", "0", "use a GLSL postprocessing shader"};
196 cvar_t r_glsl_postprocess_uservec1 = {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)"};
197 cvar_t r_glsl_postprocess_uservec2 = {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)"};
198 cvar_t r_glsl_postprocess_uservec3 = {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)"};
199 cvar_t r_glsl_postprocess_uservec4 = {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)"};
200 cvar_t r_glsl_postprocess_uservec1_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec1_enable", "1", "enables postprocessing uservec1 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
201 cvar_t r_glsl_postprocess_uservec2_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec2_enable", "1", "enables postprocessing uservec2 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
202 cvar_t r_glsl_postprocess_uservec3_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec3_enable", "1", "enables postprocessing uservec3 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
203 cvar_t r_glsl_postprocess_uservec4_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec4_enable", "1", "enables postprocessing uservec4 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
205 cvar_t r_water = {CVAR_SAVE, "r_water", "0", "whether to use reflections and refraction on water surfaces (note: r_wateralpha must be set below 1)"};
206 cvar_t r_water_cameraentitiesonly = {CVAR_SAVE, "r_water_cameraentitiesonly", "0", "whether to only show QC-defined reflections/refractions (typically used for camera- or portal-like effects)"};
207 cvar_t r_water_clippingplanebias = {CVAR_SAVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
208 cvar_t r_water_resolutionmultiplier = {CVAR_SAVE, "r_water_resolutionmultiplier", "0.5", "multiplier for screen resolution when rendering refracted/reflected scenes, 1 is full quality, lower values are faster"};
209 cvar_t r_water_refractdistort = {CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
210 cvar_t r_water_reflectdistort = {CVAR_SAVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
211 cvar_t r_water_scissormode = {0, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
212 cvar_t r_water_lowquality = {0, "r_water_lowquality", "0", "special option to accelerate water rendering, 1 disables shadows and particles, 2 disables all dynamic lights"};
213 cvar_t r_water_hideplayer = {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"};
215 cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"};
216 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
217 cvar_t r_lerplightstyles = {CVAR_SAVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
218 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
220 cvar_t r_bloom = {CVAR_SAVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
221 cvar_t r_bloom_colorscale = {CVAR_SAVE, "r_bloom_colorscale", "1", "how bright the glow is"};
223 cvar_t r_bloom_brighten = {CVAR_SAVE, "r_bloom_brighten", "2", "how bright the glow is, after subtract/power"};
224 cvar_t r_bloom_blur = {CVAR_SAVE, "r_bloom_blur", "4", "how large the glow is"};
225 cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
226 cvar_t r_bloom_colorexponent = {CVAR_SAVE, "r_bloom_colorexponent", "1", "how exaggerated the glow is"};
227 cvar_t r_bloom_colorsubtract = {CVAR_SAVE, "r_bloom_colorsubtract", "0.125", "reduces bloom colors by a certain amount"};
228 cvar_t r_bloom_scenebrightness = {CVAR_SAVE, "r_bloom_scenebrightness", "1", "global rendering brightness when bloom is enabled"};
230 cvar_t r_hdr_scenebrightness = {CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
231 cvar_t r_hdr_glowintensity = {CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
232 cvar_t r_hdr_irisadaptation = {CVAR_SAVE, "r_hdr_irisadaptation", "0", "adjust scene brightness according to light intensity at player location"};
233 cvar_t r_hdr_irisadaptation_multiplier = {CVAR_SAVE, "r_hdr_irisadaptation_multiplier", "2", "brightness at which value will be 1.0"};
234 cvar_t r_hdr_irisadaptation_minvalue = {CVAR_SAVE, "r_hdr_irisadaptation_minvalue", "0.5", "minimum value that can result from multiplier / brightness"};
235 cvar_t r_hdr_irisadaptation_maxvalue = {CVAR_SAVE, "r_hdr_irisadaptation_maxvalue", "4", "maximum value that can result from multiplier / brightness"};
236 cvar_t r_hdr_irisadaptation_value = {0, "r_hdr_irisadaptation_value", "1", "current value as scenebrightness multiplier, changes continuously when irisadaptation is active"};
237 cvar_t r_hdr_irisadaptation_fade_up = {CVAR_SAVE, "r_hdr_irisadaptation_fade_up", "0.1", "fade rate at which value adjusts to darkness"};
238 cvar_t r_hdr_irisadaptation_fade_down = {CVAR_SAVE, "r_hdr_irisadaptation_fade_down", "0.5", "fade rate at which value adjusts to brightness"};
239 cvar_t r_hdr_irisadaptation_radius = {CVAR_SAVE, "r_hdr_irisadaptation_radius", "15", "lighting within this many units of the eye is averaged"};
241 cvar_t r_smoothnormals_areaweighting = {0, "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"};
243 cvar_t developer_texturelogging = {0, "developer_texturelogging", "0", "produces a textures.log file containing names of skins and map textures the engine tried to load"};
245 cvar_t gl_lightmaps = {0, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers), a value of 2 keeps normalmap shading"};
247 cvar_t r_test = {0, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
249 cvar_t r_batch_multidraw = {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)"};
250 cvar_t r_batch_multidraw_mintriangles = {CVAR_SAVE, "r_batch_multidraw_mintriangles", "0", "minimum number of triangles to activate multidraw path (copying small groups of triangles may be faster)"};
251 cvar_t r_batch_debugdynamicvertexpath = {CVAR_SAVE, "r_batch_debugdynamicvertexpath", "0", "force the dynamic batching code path for debugging purposes"};
252 cvar_t r_batch_dynamicbuffer = {CVAR_SAVE, "r_batch_dynamicbuffer", "0", "use vertex/index buffers for drawing dynamic and copytriangles batches"};
254 cvar_t r_glsl_saturation = {CVAR_SAVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
255 cvar_t r_glsl_saturation_redcompensate = {CVAR_SAVE, "r_glsl_saturation_redcompensate", "0", "a 'vampire sight' addition to desaturation effect, does compensation for red color, r_glsl_restart is required"};
257 cvar_t r_glsl_vertextextureblend_usebothalphas = {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."};
259 cvar_t r_framedatasize = {CVAR_SAVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"};
260 cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
262 {CVAR_SAVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"},
263 {CVAR_SAVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"},
264 {CVAR_SAVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"},
265 {CVAR_SAVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
268 extern cvar_t v_glslgamma_2d;
270 extern qboolean v_flipped_state;
272 r_framebufferstate_t r_fb;
274 /// shadow volume bsp struct with automatically growing nodes buffer
277 int r_uniformbufferalignment = 32; // dynamically updated to match GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
279 rtexture_t *r_texture_blanknormalmap;
280 rtexture_t *r_texture_white;
281 rtexture_t *r_texture_grey128;
282 rtexture_t *r_texture_black;
283 rtexture_t *r_texture_notexture;
284 rtexture_t *r_texture_whitecube;
285 rtexture_t *r_texture_normalizationcube;
286 rtexture_t *r_texture_fogattenuation;
287 rtexture_t *r_texture_fogheighttexture;
288 rtexture_t *r_texture_gammaramps;
289 unsigned int r_texture_gammaramps_serial;
290 //rtexture_t *r_texture_fogintensity;
291 rtexture_t *r_texture_reflectcube;
293 // TODO: hash lookups?
294 typedef struct cubemapinfo_s
301 int r_texture_numcubemaps;
302 cubemapinfo_t *r_texture_cubemaps[MAX_CUBEMAPS];
304 unsigned int r_queries[MAX_OCCLUSION_QUERIES];
305 unsigned int r_numqueries;
306 unsigned int r_maxqueries;
308 typedef struct r_qwskincache_s
310 char name[MAX_QPATH];
311 skinframe_t *skinframe;
315 static r_qwskincache_t *r_qwskincache;
316 static int r_qwskincache_size;
318 /// vertex coordinates for a quad that covers the screen exactly
319 extern const float r_screenvertex3f[12];
320 const float r_screenvertex3f[12] =
328 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
331 for (i = 0;i < verts;i++)
342 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
345 for (i = 0;i < verts;i++)
355 // FIXME: move this to client?
358 if (gamemode == GAME_NEHAHRA)
360 Cvar_Set("gl_fogenable", "0");
361 Cvar_Set("gl_fogdensity", "0.2");
362 Cvar_Set("gl_fogred", "0.3");
363 Cvar_Set("gl_foggreen", "0.3");
364 Cvar_Set("gl_fogblue", "0.3");
366 r_refdef.fog_density = 0;
367 r_refdef.fog_red = 0;
368 r_refdef.fog_green = 0;
369 r_refdef.fog_blue = 0;
370 r_refdef.fog_alpha = 1;
371 r_refdef.fog_start = 0;
372 r_refdef.fog_end = 16384;
373 r_refdef.fog_height = 1<<30;
374 r_refdef.fog_fadedepth = 128;
375 memset(r_refdef.fog_height_texturename, 0, sizeof(r_refdef.fog_height_texturename));
378 static void R_BuildBlankTextures(void)
380 unsigned char data[4];
381 data[2] = 128; // normal X
382 data[1] = 128; // normal Y
383 data[0] = 255; // normal Z
384 data[3] = 255; // height
385 r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
390 r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
395 r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
400 r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
403 static void R_BuildNoTexture(void)
406 unsigned char pix[16][16][4];
407 // this makes a light grey/dark grey checkerboard texture
408 for (y = 0;y < 16;y++)
410 for (x = 0;x < 16;x++)
412 if ((y < 8) ^ (x < 8))
428 r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, -1, NULL);
431 static void R_BuildWhiteCube(void)
433 unsigned char data[6*1*1*4];
434 memset(data, 255, sizeof(data));
435 r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
438 static void R_BuildNormalizationCube(void)
442 vec_t s, t, intensity;
445 data = (unsigned char *)Mem_Alloc(tempmempool, 6*NORMSIZE*NORMSIZE*4);
446 for (side = 0;side < 6;side++)
448 for (y = 0;y < NORMSIZE;y++)
450 for (x = 0;x < NORMSIZE;x++)
452 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
453 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
488 intensity = 127.0f / sqrt(DotProduct(v, v));
489 data[((side*64+y)*64+x)*4+2] = (unsigned char)(128.0f + intensity * v[0]);
490 data[((side*64+y)*64+x)*4+1] = (unsigned char)(128.0f + intensity * v[1]);
491 data[((side*64+y)*64+x)*4+0] = (unsigned char)(128.0f + intensity * v[2]);
492 data[((side*64+y)*64+x)*4+3] = 255;
496 r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
500 static void R_BuildFogTexture(void)
504 unsigned char data1[FOGWIDTH][4];
505 //unsigned char data2[FOGWIDTH][4];
508 r_refdef.fogmasktable_start = r_refdef.fog_start;
509 r_refdef.fogmasktable_alpha = r_refdef.fog_alpha;
510 r_refdef.fogmasktable_range = r_refdef.fogrange;
511 r_refdef.fogmasktable_density = r_refdef.fog_density;
513 r = r_refdef.fogmasktable_range / FOGMASKTABLEWIDTH;
514 for (x = 0;x < FOGMASKTABLEWIDTH;x++)
516 d = (x * r - r_refdef.fogmasktable_start);
517 if(developer_extra.integer)
518 Con_DPrintf("%f ", d);
520 if (r_fog_exp2.integer)
521 alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d);
523 alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d);
524 if(developer_extra.integer)
525 Con_DPrintf(" : %f ", alpha);
526 alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha;
527 if(developer_extra.integer)
528 Con_DPrintf(" = %f\n", alpha);
529 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
532 for (x = 0;x < FOGWIDTH;x++)
534 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
539 //data2[x][0] = 255 - b;
540 //data2[x][1] = 255 - b;
541 //data2[x][2] = 255 - b;
544 if (r_texture_fogattenuation)
546 R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
547 //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
551 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
552 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
556 static void R_BuildFogHeightTexture(void)
558 unsigned char *inpixels;
566 strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename));
567 if (r_refdef.fogheighttexturename[0])
568 inpixels = loadimagepixelsbgra(r_refdef.fogheighttexturename, true, false, false, NULL);
571 r_refdef.fog_height_tablesize = 0;
572 if (r_texture_fogheighttexture)
573 R_FreeTexture(r_texture_fogheighttexture);
574 r_texture_fogheighttexture = NULL;
575 if (r_refdef.fog_height_table2d)
576 Mem_Free(r_refdef.fog_height_table2d);
577 r_refdef.fog_height_table2d = NULL;
578 if (r_refdef.fog_height_table1d)
579 Mem_Free(r_refdef.fog_height_table1d);
580 r_refdef.fog_height_table1d = NULL;
584 r_refdef.fog_height_tablesize = size;
585 r_refdef.fog_height_table1d = (unsigned char *)Mem_Alloc(r_main_mempool, size * 4);
586 r_refdef.fog_height_table2d = (unsigned char *)Mem_Alloc(r_main_mempool, size * size * 4);
587 memcpy(r_refdef.fog_height_table1d, inpixels, size * 4);
589 // LordHavoc: now the magic - what is that table2d for? it is a cooked
590 // average fog color table accounting for every fog layer between a point
591 // and the camera. (Note: attenuation is handled separately!)
592 for (y = 0;y < size;y++)
594 for (x = 0;x < size;x++)
600 for (j = x;j <= y;j++)
602 Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
608 for (j = x;j >= y;j--)
610 Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
615 r_refdef.fog_height_table2d[(y*size+x)*4+0] = (unsigned char)(c[0] * f);
616 r_refdef.fog_height_table2d[(y*size+x)*4+1] = (unsigned char)(c[1] * f);
617 r_refdef.fog_height_table2d[(y*size+x)*4+2] = (unsigned char)(c[2] * f);
618 r_refdef.fog_height_table2d[(y*size+x)*4+3] = (unsigned char)(c[3] * f);
621 r_texture_fogheighttexture = R_LoadTexture2D(r_main_texturepool, "fogheighttable", size, size, r_refdef.fog_height_table2d, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_CLAMP, -1, NULL);
624 //=======================================================================================================================================================
626 static const char *builtinshaderstrings[] =
628 #include "shader_glsl.h"
632 //=======================================================================================================================================================
634 typedef struct shaderpermutationinfo_s
639 shaderpermutationinfo_t;
641 typedef struct shadermodeinfo_s
643 const char *sourcebasename;
644 const char *extension;
645 const char **builtinshaderstrings;
654 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
655 shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
657 {"#define USEDIFFUSE\n", " diffuse"},
658 {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
659 {"#define USEVIEWTINT\n", " viewtint"},
660 {"#define USECOLORMAPPING\n", " colormapping"},
661 {"#define USESATURATION\n", " saturation"},
662 {"#define USEFOGINSIDE\n", " foginside"},
663 {"#define USEFOGOUTSIDE\n", " fogoutside"},
664 {"#define USEFOGHEIGHTTEXTURE\n", " fogheighttexture"},
665 {"#define USEFOGALPHAHACK\n", " fogalphahack"},
666 {"#define USEGAMMARAMPS\n", " gammaramps"},
667 {"#define USECUBEFILTER\n", " cubefilter"},
668 {"#define USEGLOW\n", " glow"},
669 {"#define USEBLOOM\n", " bloom"},
670 {"#define USESPECULAR\n", " specular"},
671 {"#define USEPOSTPROCESSING\n", " postprocessing"},
672 {"#define USEREFLECTION\n", " reflection"},
673 {"#define USEOFFSETMAPPING\n", " offsetmapping"},
674 {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
675 {"#define USESHADOWMAP2D\n", " shadowmap2d"},
676 {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm
677 {"#define USESHADOWMAPORTHO\n", " shadowmaportho"},
678 {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
679 {"#define USEALPHAKILL\n", " alphakill"},
680 {"#define USEREFLECTCUBE\n", " reflectcube"},
681 {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"},
682 {"#define USEBOUNCEGRID\n", " bouncegrid"},
683 {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm
684 {"#define USETRIPPY\n", " trippy"},
685 {"#define USEDEPTHRGB\n", " depthrgb"},
686 {"#define USEALPHAGENVERTEX\n", " alphagenvertex"},
687 {"#define USESKELETAL\n", " skeletal"},
688 {"#define USEOCCLUDE\n", " occlude"}
691 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
692 shadermodeinfo_t shadermodeinfo[SHADERLANGUAGE_COUNT][SHADERMODE_COUNT] =
694 // SHADERLANGUAGE_GLSL
696 {"combined", "glsl", builtinshaderstrings, "#define MODE_GENERIC\n", " generic"},
697 {"combined", "glsl", builtinshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
698 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
699 {"combined", "glsl", builtinshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
700 {"combined", "glsl", builtinshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
701 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
702 {"combined", "glsl", builtinshaderstrings, "#define MODE_FAKELIGHT\n", " fakelight"},
703 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
704 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
705 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
706 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
707 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
708 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
709 {"combined", "glsl", builtinshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
710 {"combined", "glsl", builtinshaderstrings, "#define MODE_WATER\n", " water"},
711 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
712 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
716 struct r_glsl_permutation_s;
717 typedef struct r_glsl_permutation_s
720 struct r_glsl_permutation_s *hashnext;
722 dpuint64 permutation;
724 /// indicates if we have tried compiling this permutation already
726 /// 0 if compilation failed
728 // texture units assigned to each detected uniform
729 int tex_Texture_First;
730 int tex_Texture_Second;
731 int tex_Texture_GammaRamps;
732 int tex_Texture_Normal;
733 int tex_Texture_Color;
734 int tex_Texture_Gloss;
735 int tex_Texture_Glow;
736 int tex_Texture_SecondaryNormal;
737 int tex_Texture_SecondaryColor;
738 int tex_Texture_SecondaryGloss;
739 int tex_Texture_SecondaryGlow;
740 int tex_Texture_Pants;
741 int tex_Texture_Shirt;
742 int tex_Texture_FogHeightTexture;
743 int tex_Texture_FogMask;
744 int tex_Texture_Lightmap;
745 int tex_Texture_Deluxemap;
746 int tex_Texture_Attenuation;
747 int tex_Texture_Cube;
748 int tex_Texture_Refraction;
749 int tex_Texture_Reflection;
750 int tex_Texture_ShadowMap2D;
751 int tex_Texture_CubeProjection;
752 int tex_Texture_ScreenNormalMap;
753 int tex_Texture_ScreenDiffuse;
754 int tex_Texture_ScreenSpecular;
755 int tex_Texture_ReflectMask;
756 int tex_Texture_ReflectCube;
757 int tex_Texture_BounceGrid;
758 /// locations of detected uniforms in program object, or -1 if not found
759 int loc_Texture_First;
760 int loc_Texture_Second;
761 int loc_Texture_GammaRamps;
762 int loc_Texture_Normal;
763 int loc_Texture_Color;
764 int loc_Texture_Gloss;
765 int loc_Texture_Glow;
766 int loc_Texture_SecondaryNormal;
767 int loc_Texture_SecondaryColor;
768 int loc_Texture_SecondaryGloss;
769 int loc_Texture_SecondaryGlow;
770 int loc_Texture_Pants;
771 int loc_Texture_Shirt;
772 int loc_Texture_FogHeightTexture;
773 int loc_Texture_FogMask;
774 int loc_Texture_Lightmap;
775 int loc_Texture_Deluxemap;
776 int loc_Texture_Attenuation;
777 int loc_Texture_Cube;
778 int loc_Texture_Refraction;
779 int loc_Texture_Reflection;
780 int loc_Texture_ShadowMap2D;
781 int loc_Texture_CubeProjection;
782 int loc_Texture_ScreenNormalMap;
783 int loc_Texture_ScreenDiffuse;
784 int loc_Texture_ScreenSpecular;
785 int loc_Texture_ReflectMask;
786 int loc_Texture_ReflectCube;
787 int loc_Texture_BounceGrid;
789 int loc_BloomBlur_Parameters;
791 int loc_Color_Ambient;
792 int loc_Color_Diffuse;
793 int loc_Color_Specular;
797 int loc_DeferredColor_Ambient;
798 int loc_DeferredColor_Diffuse;
799 int loc_DeferredColor_Specular;
800 int loc_DeferredMod_Diffuse;
801 int loc_DeferredMod_Specular;
802 int loc_DistortScaleRefractReflect;
805 int loc_FogHeightFade;
807 int loc_FogPlaneViewDist;
808 int loc_FogRangeRecip;
811 int loc_LightPosition;
812 int loc_OffsetMapping_ScaleSteps;
813 int loc_OffsetMapping_LodDistance;
814 int loc_OffsetMapping_Bias;
816 int loc_ReflectColor;
817 int loc_ReflectFactor;
818 int loc_ReflectOffset;
819 int loc_RefractColor;
821 int loc_ScreenCenterRefractReflect;
822 int loc_ScreenScaleRefractReflect;
823 int loc_ScreenToDepth;
824 int loc_ShadowMap_Parameters;
825 int loc_ShadowMap_TextureScale;
826 int loc_SpecularPower;
827 int loc_Skeletal_Transform12;
832 int loc_ViewTintColor;
834 int loc_ModelToLight;
836 int loc_BackgroundTexMatrix;
837 int loc_ModelViewProjectionMatrix;
838 int loc_ModelViewMatrix;
839 int loc_PixelToScreenTexCoord;
840 int loc_ModelToReflectCube;
841 int loc_ShadowMapMatrix;
842 int loc_BloomColorSubtract;
843 int loc_NormalmapScrollBlend;
844 int loc_BounceGridMatrix;
845 int loc_BounceGridIntensity;
846 /// uniform block bindings
847 int ubibind_Skeletal_Transform12_UniformBlock;
848 /// uniform block indices
849 int ubiloc_Skeletal_Transform12_UniformBlock;
851 r_glsl_permutation_t;
853 #define SHADERPERMUTATION_HASHSIZE 256
856 // non-degradable "lightweight" shader parameters to keep the permutations simpler
857 // these can NOT degrade! only use for simple stuff
860 SHADERSTATICPARM_SATURATION_REDCOMPENSATE = 0, ///< red compensation filter for saturation
861 SHADERSTATICPARM_EXACTSPECULARMATH = 1, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
862 SHADERSTATICPARM_POSTPROCESS_USERVEC1 = 2, ///< postprocess uservec1 is enabled
863 SHADERSTATICPARM_POSTPROCESS_USERVEC2 = 3, ///< postprocess uservec2 is enabled
864 SHADERSTATICPARM_POSTPROCESS_USERVEC3 = 4, ///< postprocess uservec3 is enabled
865 SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5, ///< postprocess uservec4 is enabled
866 SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending
867 SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7, ///< LOD for offsetmapping
868 SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1
869 SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2
870 SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
871 SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
872 SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
873 SHADERSTATICPARM_FXAA = 13 ///< fast approximate anti aliasing
875 #define SHADERSTATICPARMS_COUNT 14
877 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
878 static int shaderstaticparms_count = 0;
880 static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0};
881 #define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F))
883 extern qboolean r_shadow_shadowmapsampler;
884 extern int r_shadow_shadowmappcf;
885 qboolean R_CompileShader_CheckStaticParms(void)
887 static int r_compileshader_staticparms_save[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5];
888 memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
889 memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
892 if (r_glsl_saturation_redcompensate.integer)
893 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SATURATION_REDCOMPENSATE);
894 if (r_glsl_vertextextureblend_usebothalphas.integer)
895 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS);
896 if (r_shadow_glossexact.integer)
897 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_EXACTSPECULARMATH);
898 if (r_glsl_postprocess.integer)
900 if (r_glsl_postprocess_uservec1_enable.integer)
901 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC1);
902 if (r_glsl_postprocess_uservec2_enable.integer)
903 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC2);
904 if (r_glsl_postprocess_uservec3_enable.integer)
905 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC3);
906 if (r_glsl_postprocess_uservec4_enable.integer)
907 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
910 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_FXAA);
911 if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
912 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
914 if (r_shadow_shadowmapsampler)
915 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER);
916 if (r_shadow_shadowmappcf > 1)
917 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2);
918 else if (r_shadow_shadowmappcf)
919 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1);
920 if (r_celshading.integer)
921 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING);
922 if (r_celoutlines.integer)
923 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES);
925 return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
928 #define R_COMPILESHADER_STATICPARM_EMIT(p, n) \
929 if(r_compileshader_staticparms[(p) >> 5] & (1 << ((p) & 0x1F))) \
930 shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \
932 shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n"
933 static void R_CompileShader_AddStaticParms(unsigned int mode, dpuint64 permutation)
935 shaderstaticparms_count = 0;
938 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SATURATION_REDCOMPENSATE, "SATURATION_REDCOMPENSATE");
939 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_EXACTSPECULARMATH, "USEEXACTSPECULARMATH");
940 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC1, "USERVEC1");
941 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC2, "USERVEC2");
942 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC3, "USERVEC3");
943 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4");
944 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS");
945 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD");
946 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1");
947 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2");
948 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
949 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
950 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
951 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
954 /// information about each possible shader permutation
955 r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
956 /// currently selected permutation
957 r_glsl_permutation_t *r_glsl_permutation;
958 /// storage for permutations linked in the hash table
959 memexpandablearray_t r_glsl_permutationarray;
961 static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, dpuint64 permutation)
963 //unsigned int hashdepth = 0;
964 unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
965 r_glsl_permutation_t *p;
966 for (p = r_glsl_permutationhash[mode][hashindex];p;p = p->hashnext)
968 if (p->mode == mode && p->permutation == permutation)
970 //if (hashdepth > 10)
971 // Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
976 p = (r_glsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_glsl_permutationarray);
978 p->permutation = permutation;
979 p->hashnext = r_glsl_permutationhash[mode][hashindex];
980 r_glsl_permutationhash[mode][hashindex] = p;
981 //if (hashdepth > 10)
982 // Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
986 static char *R_ShaderStrCat(const char **strings)
989 const char **p = strings;
992 for (p = strings;(t = *p);p++)
995 s = string = (char *)Mem_Alloc(r_main_mempool, len);
997 for (p = strings;(t = *p);p++)
1007 static char *R_ShaderStrCat(const char **strings);
1008 static void R_InitShaderModeInfo(void)
1011 shadermodeinfo_t *modeinfo;
1012 // 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)
1013 for (language = 0; language < SHADERLANGUAGE_COUNT; language++)
1015 for (i = 0; i < SHADERMODE_COUNT; i++)
1017 char filename[MAX_QPATH];
1018 modeinfo = &shadermodeinfo[language][i];
1019 modeinfo->builtinstring = R_ShaderStrCat(modeinfo->builtinshaderstrings);
1020 modeinfo->builtincrc = CRC_Block((const unsigned char *)modeinfo->builtinstring, strlen(modeinfo->builtinstring));
1021 dpsnprintf(filename, sizeof(filename), "%s/%s_crc%i.%s", modeinfo->extension, modeinfo->sourcebasename, modeinfo->builtincrc, modeinfo->extension);
1022 modeinfo->filename = Mem_strdup(r_main_mempool, filename);
1027 static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qboolean printfromdisknotice, qboolean builtinonly)
1030 // if the mode has no filename we have to return the builtin string
1031 if (builtinonly || !modeinfo->filename)
1032 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1033 // note that FS_LoadFile appends a 0 byte to make it a valid string
1034 shaderstring = (char *)FS_LoadFile(modeinfo->filename, r_main_mempool, false, NULL);
1037 if (printfromdisknotice)
1038 Con_DPrintf("Loading shaders from file %s...\n", modeinfo->filename);
1039 return shaderstring;
1041 // fall back to builtinstring
1042 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1045 static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, dpuint64 permutation)
1050 shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode];
1052 char permutationname[256];
1053 int vertstrings_count = 0;
1054 int geomstrings_count = 0;
1055 int fragstrings_count = 0;
1056 const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1057 const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1058 const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1065 permutationname[0] = 0;
1066 sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false);
1068 strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
1070 // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object)
1071 if(vid.support.glshaderversion >= 140)
1073 vertstrings_list[vertstrings_count++] = "#version 140\n";
1074 geomstrings_list[geomstrings_count++] = "#version 140\n";
1075 fragstrings_list[fragstrings_count++] = "#version 140\n";
1076 vertstrings_list[vertstrings_count++] = "#define GLSL140\n";
1077 geomstrings_list[geomstrings_count++] = "#define GLSL140\n";
1078 fragstrings_list[fragstrings_count++] = "#define GLSL140\n";
1080 // if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad)
1081 else if(vid.support.glshaderversion >= 130)
1083 vertstrings_list[vertstrings_count++] = "#version 130\n";
1084 geomstrings_list[geomstrings_count++] = "#version 130\n";
1085 fragstrings_list[fragstrings_count++] = "#version 130\n";
1086 vertstrings_list[vertstrings_count++] = "#define GLSL130\n";
1087 geomstrings_list[geomstrings_count++] = "#define GLSL130\n";
1088 fragstrings_list[fragstrings_count++] = "#define GLSL130\n";
1090 // if we can do #version 120, we should (this adds the invariant keyword)
1091 else if(vid.support.glshaderversion >= 120)
1093 vertstrings_list[vertstrings_count++] = "#version 120\n";
1094 geomstrings_list[geomstrings_count++] = "#version 120\n";
1095 fragstrings_list[fragstrings_count++] = "#version 120\n";
1096 vertstrings_list[vertstrings_count++] = "#define GLSL120\n";
1097 geomstrings_list[geomstrings_count++] = "#define GLSL120\n";
1098 fragstrings_list[fragstrings_count++] = "#define GLSL120\n";
1100 // GLES also adds several things from GLSL120
1101 switch(vid.renderpath)
1103 case RENDERPATH_GLES2:
1104 vertstrings_list[vertstrings_count++] = "#define GLES\n";
1105 geomstrings_list[geomstrings_count++] = "#define GLES\n";
1106 fragstrings_list[fragstrings_count++] = "#define GLES\n";
1112 // the first pretext is which type of shader to compile as
1113 // (later these will all be bound together as a program object)
1114 vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
1115 geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
1116 fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
1118 // the second pretext is the mode (for example a light source)
1119 vertstrings_list[vertstrings_count++] = modeinfo->pretext;
1120 geomstrings_list[geomstrings_count++] = modeinfo->pretext;
1121 fragstrings_list[fragstrings_count++] = modeinfo->pretext;
1122 strlcat(permutationname, modeinfo->name, sizeof(permutationname));
1124 // now add all the permutation pretexts
1125 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1127 if (permutation & (1ll<<i))
1129 vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
1130 geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
1131 fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
1132 strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
1136 // keep line numbers correct
1137 vertstrings_list[vertstrings_count++] = "\n";
1138 geomstrings_list[geomstrings_count++] = "\n";
1139 fragstrings_list[fragstrings_count++] = "\n";
1144 R_CompileShader_AddStaticParms(mode, permutation);
1145 memcpy((char *)(vertstrings_list + vertstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1146 vertstrings_count += shaderstaticparms_count;
1147 memcpy((char *)(geomstrings_list + geomstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1148 geomstrings_count += shaderstaticparms_count;
1149 memcpy((char *)(fragstrings_list + fragstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1150 fragstrings_count += shaderstaticparms_count;
1152 // now append the shader text itself
1153 vertstrings_list[vertstrings_count++] = sourcestring;
1154 geomstrings_list[geomstrings_count++] = sourcestring;
1155 fragstrings_list[fragstrings_count++] = sourcestring;
1157 // compile the shader program
1158 if (vertstrings_count + geomstrings_count + fragstrings_count)
1159 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1163 qglUseProgram(p->program);CHECKGLERROR
1164 // look up all the uniform variable names we care about, so we don't
1165 // have to look them up every time we set them
1170 GLint activeuniformindex = 0;
1171 GLint numactiveuniforms = 0;
1172 char uniformname[128];
1173 GLsizei uniformnamelength = 0;
1174 GLint uniformsize = 0;
1175 GLenum uniformtype = 0;
1176 memset(uniformname, 0, sizeof(uniformname));
1177 qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms);
1178 Con_Printf("Shader has %i uniforms\n", numactiveuniforms);
1179 for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++)
1181 qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname);
1182 Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype);
1187 p->loc_Texture_First = qglGetUniformLocation(p->program, "Texture_First");
1188 p->loc_Texture_Second = qglGetUniformLocation(p->program, "Texture_Second");
1189 p->loc_Texture_GammaRamps = qglGetUniformLocation(p->program, "Texture_GammaRamps");
1190 p->loc_Texture_Normal = qglGetUniformLocation(p->program, "Texture_Normal");
1191 p->loc_Texture_Color = qglGetUniformLocation(p->program, "Texture_Color");
1192 p->loc_Texture_Gloss = qglGetUniformLocation(p->program, "Texture_Gloss");
1193 p->loc_Texture_Glow = qglGetUniformLocation(p->program, "Texture_Glow");
1194 p->loc_Texture_SecondaryNormal = qglGetUniformLocation(p->program, "Texture_SecondaryNormal");
1195 p->loc_Texture_SecondaryColor = qglGetUniformLocation(p->program, "Texture_SecondaryColor");
1196 p->loc_Texture_SecondaryGloss = qglGetUniformLocation(p->program, "Texture_SecondaryGloss");
1197 p->loc_Texture_SecondaryGlow = qglGetUniformLocation(p->program, "Texture_SecondaryGlow");
1198 p->loc_Texture_Pants = qglGetUniformLocation(p->program, "Texture_Pants");
1199 p->loc_Texture_Shirt = qglGetUniformLocation(p->program, "Texture_Shirt");
1200 p->loc_Texture_FogHeightTexture = qglGetUniformLocation(p->program, "Texture_FogHeightTexture");
1201 p->loc_Texture_FogMask = qglGetUniformLocation(p->program, "Texture_FogMask");
1202 p->loc_Texture_Lightmap = qglGetUniformLocation(p->program, "Texture_Lightmap");
1203 p->loc_Texture_Deluxemap = qglGetUniformLocation(p->program, "Texture_Deluxemap");
1204 p->loc_Texture_Attenuation = qglGetUniformLocation(p->program, "Texture_Attenuation");
1205 p->loc_Texture_Cube = qglGetUniformLocation(p->program, "Texture_Cube");
1206 p->loc_Texture_Refraction = qglGetUniformLocation(p->program, "Texture_Refraction");
1207 p->loc_Texture_Reflection = qglGetUniformLocation(p->program, "Texture_Reflection");
1208 p->loc_Texture_ShadowMap2D = qglGetUniformLocation(p->program, "Texture_ShadowMap2D");
1209 p->loc_Texture_CubeProjection = qglGetUniformLocation(p->program, "Texture_CubeProjection");
1210 p->loc_Texture_ScreenNormalMap = qglGetUniformLocation(p->program, "Texture_ScreenNormalMap");
1211 p->loc_Texture_ScreenDiffuse = qglGetUniformLocation(p->program, "Texture_ScreenDiffuse");
1212 p->loc_Texture_ScreenSpecular = qglGetUniformLocation(p->program, "Texture_ScreenSpecular");
1213 p->loc_Texture_ReflectMask = qglGetUniformLocation(p->program, "Texture_ReflectMask");
1214 p->loc_Texture_ReflectCube = qglGetUniformLocation(p->program, "Texture_ReflectCube");
1215 p->loc_Texture_BounceGrid = qglGetUniformLocation(p->program, "Texture_BounceGrid");
1216 p->loc_Alpha = qglGetUniformLocation(p->program, "Alpha");
1217 p->loc_BloomBlur_Parameters = qglGetUniformLocation(p->program, "BloomBlur_Parameters");
1218 p->loc_ClientTime = qglGetUniformLocation(p->program, "ClientTime");
1219 p->loc_Color_Ambient = qglGetUniformLocation(p->program, "Color_Ambient");
1220 p->loc_Color_Diffuse = qglGetUniformLocation(p->program, "Color_Diffuse");
1221 p->loc_Color_Specular = qglGetUniformLocation(p->program, "Color_Specular");
1222 p->loc_Color_Glow = qglGetUniformLocation(p->program, "Color_Glow");
1223 p->loc_Color_Pants = qglGetUniformLocation(p->program, "Color_Pants");
1224 p->loc_Color_Shirt = qglGetUniformLocation(p->program, "Color_Shirt");
1225 p->loc_DeferredColor_Ambient = qglGetUniformLocation(p->program, "DeferredColor_Ambient");
1226 p->loc_DeferredColor_Diffuse = qglGetUniformLocation(p->program, "DeferredColor_Diffuse");
1227 p->loc_DeferredColor_Specular = qglGetUniformLocation(p->program, "DeferredColor_Specular");
1228 p->loc_DeferredMod_Diffuse = qglGetUniformLocation(p->program, "DeferredMod_Diffuse");
1229 p->loc_DeferredMod_Specular = qglGetUniformLocation(p->program, "DeferredMod_Specular");
1230 p->loc_DistortScaleRefractReflect = qglGetUniformLocation(p->program, "DistortScaleRefractReflect");
1231 p->loc_EyePosition = qglGetUniformLocation(p->program, "EyePosition");
1232 p->loc_FogColor = qglGetUniformLocation(p->program, "FogColor");
1233 p->loc_FogHeightFade = qglGetUniformLocation(p->program, "FogHeightFade");
1234 p->loc_FogPlane = qglGetUniformLocation(p->program, "FogPlane");
1235 p->loc_FogPlaneViewDist = qglGetUniformLocation(p->program, "FogPlaneViewDist");
1236 p->loc_FogRangeRecip = qglGetUniformLocation(p->program, "FogRangeRecip");
1237 p->loc_LightColor = qglGetUniformLocation(p->program, "LightColor");
1238 p->loc_LightDir = qglGetUniformLocation(p->program, "LightDir");
1239 p->loc_LightPosition = qglGetUniformLocation(p->program, "LightPosition");
1240 p->loc_OffsetMapping_ScaleSteps = qglGetUniformLocation(p->program, "OffsetMapping_ScaleSteps");
1241 p->loc_OffsetMapping_LodDistance = qglGetUniformLocation(p->program, "OffsetMapping_LodDistance");
1242 p->loc_OffsetMapping_Bias = qglGetUniformLocation(p->program, "OffsetMapping_Bias");
1243 p->loc_PixelSize = qglGetUniformLocation(p->program, "PixelSize");
1244 p->loc_ReflectColor = qglGetUniformLocation(p->program, "ReflectColor");
1245 p->loc_ReflectFactor = qglGetUniformLocation(p->program, "ReflectFactor");
1246 p->loc_ReflectOffset = qglGetUniformLocation(p->program, "ReflectOffset");
1247 p->loc_RefractColor = qglGetUniformLocation(p->program, "RefractColor");
1248 p->loc_Saturation = qglGetUniformLocation(p->program, "Saturation");
1249 p->loc_ScreenCenterRefractReflect = qglGetUniformLocation(p->program, "ScreenCenterRefractReflect");
1250 p->loc_ScreenScaleRefractReflect = qglGetUniformLocation(p->program, "ScreenScaleRefractReflect");
1251 p->loc_ScreenToDepth = qglGetUniformLocation(p->program, "ScreenToDepth");
1252 p->loc_ShadowMap_Parameters = qglGetUniformLocation(p->program, "ShadowMap_Parameters");
1253 p->loc_ShadowMap_TextureScale = qglGetUniformLocation(p->program, "ShadowMap_TextureScale");
1254 p->loc_SpecularPower = qglGetUniformLocation(p->program, "SpecularPower");
1255 p->loc_UserVec1 = qglGetUniformLocation(p->program, "UserVec1");
1256 p->loc_UserVec2 = qglGetUniformLocation(p->program, "UserVec2");
1257 p->loc_UserVec3 = qglGetUniformLocation(p->program, "UserVec3");
1258 p->loc_UserVec4 = qglGetUniformLocation(p->program, "UserVec4");
1259 p->loc_ViewTintColor = qglGetUniformLocation(p->program, "ViewTintColor");
1260 p->loc_ViewToLight = qglGetUniformLocation(p->program, "ViewToLight");
1261 p->loc_ModelToLight = qglGetUniformLocation(p->program, "ModelToLight");
1262 p->loc_TexMatrix = qglGetUniformLocation(p->program, "TexMatrix");
1263 p->loc_BackgroundTexMatrix = qglGetUniformLocation(p->program, "BackgroundTexMatrix");
1264 p->loc_ModelViewMatrix = qglGetUniformLocation(p->program, "ModelViewMatrix");
1265 p->loc_ModelViewProjectionMatrix = qglGetUniformLocation(p->program, "ModelViewProjectionMatrix");
1266 p->loc_PixelToScreenTexCoord = qglGetUniformLocation(p->program, "PixelToScreenTexCoord");
1267 p->loc_ModelToReflectCube = qglGetUniformLocation(p->program, "ModelToReflectCube");
1268 p->loc_ShadowMapMatrix = qglGetUniformLocation(p->program, "ShadowMapMatrix");
1269 p->loc_BloomColorSubtract = qglGetUniformLocation(p->program, "BloomColorSubtract");
1270 p->loc_NormalmapScrollBlend = qglGetUniformLocation(p->program, "NormalmapScrollBlend");
1271 p->loc_BounceGridMatrix = qglGetUniformLocation(p->program, "BounceGridMatrix");
1272 p->loc_BounceGridIntensity = qglGetUniformLocation(p->program, "BounceGridIntensity");
1273 // initialize the samplers to refer to the texture units we use
1274 p->tex_Texture_First = -1;
1275 p->tex_Texture_Second = -1;
1276 p->tex_Texture_GammaRamps = -1;
1277 p->tex_Texture_Normal = -1;
1278 p->tex_Texture_Color = -1;
1279 p->tex_Texture_Gloss = -1;
1280 p->tex_Texture_Glow = -1;
1281 p->tex_Texture_SecondaryNormal = -1;
1282 p->tex_Texture_SecondaryColor = -1;
1283 p->tex_Texture_SecondaryGloss = -1;
1284 p->tex_Texture_SecondaryGlow = -1;
1285 p->tex_Texture_Pants = -1;
1286 p->tex_Texture_Shirt = -1;
1287 p->tex_Texture_FogHeightTexture = -1;
1288 p->tex_Texture_FogMask = -1;
1289 p->tex_Texture_Lightmap = -1;
1290 p->tex_Texture_Deluxemap = -1;
1291 p->tex_Texture_Attenuation = -1;
1292 p->tex_Texture_Cube = -1;
1293 p->tex_Texture_Refraction = -1;
1294 p->tex_Texture_Reflection = -1;
1295 p->tex_Texture_ShadowMap2D = -1;
1296 p->tex_Texture_CubeProjection = -1;
1297 p->tex_Texture_ScreenNormalMap = -1;
1298 p->tex_Texture_ScreenDiffuse = -1;
1299 p->tex_Texture_ScreenSpecular = -1;
1300 p->tex_Texture_ReflectMask = -1;
1301 p->tex_Texture_ReflectCube = -1;
1302 p->tex_Texture_BounceGrid = -1;
1303 // bind the texture samplers in use
1305 if (p->loc_Texture_First >= 0) {p->tex_Texture_First = sampler;qglUniform1i(p->loc_Texture_First , sampler);sampler++;}
1306 if (p->loc_Texture_Second >= 0) {p->tex_Texture_Second = sampler;qglUniform1i(p->loc_Texture_Second , sampler);sampler++;}
1307 if (p->loc_Texture_GammaRamps >= 0) {p->tex_Texture_GammaRamps = sampler;qglUniform1i(p->loc_Texture_GammaRamps , sampler);sampler++;}
1308 if (p->loc_Texture_Normal >= 0) {p->tex_Texture_Normal = sampler;qglUniform1i(p->loc_Texture_Normal , sampler);sampler++;}
1309 if (p->loc_Texture_Color >= 0) {p->tex_Texture_Color = sampler;qglUniform1i(p->loc_Texture_Color , sampler);sampler++;}
1310 if (p->loc_Texture_Gloss >= 0) {p->tex_Texture_Gloss = sampler;qglUniform1i(p->loc_Texture_Gloss , sampler);sampler++;}
1311 if (p->loc_Texture_Glow >= 0) {p->tex_Texture_Glow = sampler;qglUniform1i(p->loc_Texture_Glow , sampler);sampler++;}
1312 if (p->loc_Texture_SecondaryNormal >= 0) {p->tex_Texture_SecondaryNormal = sampler;qglUniform1i(p->loc_Texture_SecondaryNormal , sampler);sampler++;}
1313 if (p->loc_Texture_SecondaryColor >= 0) {p->tex_Texture_SecondaryColor = sampler;qglUniform1i(p->loc_Texture_SecondaryColor , sampler);sampler++;}
1314 if (p->loc_Texture_SecondaryGloss >= 0) {p->tex_Texture_SecondaryGloss = sampler;qglUniform1i(p->loc_Texture_SecondaryGloss , sampler);sampler++;}
1315 if (p->loc_Texture_SecondaryGlow >= 0) {p->tex_Texture_SecondaryGlow = sampler;qglUniform1i(p->loc_Texture_SecondaryGlow , sampler);sampler++;}
1316 if (p->loc_Texture_Pants >= 0) {p->tex_Texture_Pants = sampler;qglUniform1i(p->loc_Texture_Pants , sampler);sampler++;}
1317 if (p->loc_Texture_Shirt >= 0) {p->tex_Texture_Shirt = sampler;qglUniform1i(p->loc_Texture_Shirt , sampler);sampler++;}
1318 if (p->loc_Texture_FogHeightTexture>= 0) {p->tex_Texture_FogHeightTexture = sampler;qglUniform1i(p->loc_Texture_FogHeightTexture, sampler);sampler++;}
1319 if (p->loc_Texture_FogMask >= 0) {p->tex_Texture_FogMask = sampler;qglUniform1i(p->loc_Texture_FogMask , sampler);sampler++;}
1320 if (p->loc_Texture_Lightmap >= 0) {p->tex_Texture_Lightmap = sampler;qglUniform1i(p->loc_Texture_Lightmap , sampler);sampler++;}
1321 if (p->loc_Texture_Deluxemap >= 0) {p->tex_Texture_Deluxemap = sampler;qglUniform1i(p->loc_Texture_Deluxemap , sampler);sampler++;}
1322 if (p->loc_Texture_Attenuation >= 0) {p->tex_Texture_Attenuation = sampler;qglUniform1i(p->loc_Texture_Attenuation , sampler);sampler++;}
1323 if (p->loc_Texture_Cube >= 0) {p->tex_Texture_Cube = sampler;qglUniform1i(p->loc_Texture_Cube , sampler);sampler++;}
1324 if (p->loc_Texture_Refraction >= 0) {p->tex_Texture_Refraction = sampler;qglUniform1i(p->loc_Texture_Refraction , sampler);sampler++;}
1325 if (p->loc_Texture_Reflection >= 0) {p->tex_Texture_Reflection = sampler;qglUniform1i(p->loc_Texture_Reflection , sampler);sampler++;}
1326 if (p->loc_Texture_ShadowMap2D >= 0) {p->tex_Texture_ShadowMap2D = sampler;qglUniform1i(p->loc_Texture_ShadowMap2D , sampler);sampler++;}
1327 if (p->loc_Texture_CubeProjection >= 0) {p->tex_Texture_CubeProjection = sampler;qglUniform1i(p->loc_Texture_CubeProjection , sampler);sampler++;}
1328 if (p->loc_Texture_ScreenNormalMap >= 0) {p->tex_Texture_ScreenNormalMap = sampler;qglUniform1i(p->loc_Texture_ScreenNormalMap , sampler);sampler++;}
1329 if (p->loc_Texture_ScreenDiffuse >= 0) {p->tex_Texture_ScreenDiffuse = sampler;qglUniform1i(p->loc_Texture_ScreenDiffuse , sampler);sampler++;}
1330 if (p->loc_Texture_ScreenSpecular >= 0) {p->tex_Texture_ScreenSpecular = sampler;qglUniform1i(p->loc_Texture_ScreenSpecular , sampler);sampler++;}
1331 if (p->loc_Texture_ReflectMask >= 0) {p->tex_Texture_ReflectMask = sampler;qglUniform1i(p->loc_Texture_ReflectMask , sampler);sampler++;}
1332 if (p->loc_Texture_ReflectCube >= 0) {p->tex_Texture_ReflectCube = sampler;qglUniform1i(p->loc_Texture_ReflectCube , sampler);sampler++;}
1333 if (p->loc_Texture_BounceGrid >= 0) {p->tex_Texture_BounceGrid = sampler;qglUniform1i(p->loc_Texture_BounceGrid , sampler);sampler++;}
1334 // get the uniform block indices so we can bind them
1335 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1336 if (vid.support.arb_uniform_buffer_object)
1337 p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
1340 p->ubiloc_Skeletal_Transform12_UniformBlock = -1;
1341 // clear the uniform block bindings
1342 p->ubibind_Skeletal_Transform12_UniformBlock = -1;
1343 // bind the uniform blocks in use
1345 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1346 if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;}
1348 // we're done compiling and setting up the shader, at least until it is used
1350 Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler);
1353 Con_Printf("^1GLSL shader %s failed! some features may not work properly.\n", permutationname);
1357 Mem_Free(sourcestring);
1360 static void R_SetupShader_SetPermutationGLSL(unsigned int mode, dpuint64 permutation)
1362 r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation);
1363 if (r_glsl_permutation != perm)
1365 r_glsl_permutation = perm;
1366 if (!r_glsl_permutation->program)
1368 if (!r_glsl_permutation->compiled)
1370 Con_DPrintf("Compiling shader mode %u permutation %u\n", mode, permutation);
1371 R_GLSL_CompilePermutation(perm, mode, permutation);
1373 if (!r_glsl_permutation->program)
1375 // remove features until we find a valid permutation
1377 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1379 // reduce i more quickly whenever it would not remove any bits
1380 dpuint64 j = 1ll<<(SHADERPERMUTATION_COUNT-1-i);
1381 if (!(permutation & j))
1384 r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1385 if (!r_glsl_permutation->compiled)
1386 R_GLSL_CompilePermutation(perm, mode, permutation);
1387 if (r_glsl_permutation->program)
1390 if (i >= SHADERPERMUTATION_COUNT)
1392 //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext);
1393 r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1394 qglUseProgram(0);CHECKGLERROR
1395 return; // no bit left to clear, entire mode is broken
1400 qglUseProgram(r_glsl_permutation->program);CHECKGLERROR
1402 if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
1403 if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
1404 if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time);
1408 void R_GLSL_Restart_f(void)
1410 unsigned int i, limit;
1411 switch(vid.renderpath)
1413 case RENDERPATH_GL20:
1414 case RENDERPATH_GLES2:
1416 r_glsl_permutation_t *p;
1417 r_glsl_permutation = NULL;
1418 limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
1419 for (i = 0;i < limit;i++)
1421 if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
1423 GL_Backend_FreeProgram(p->program);
1424 Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
1427 memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
1433 static void R_GLSL_DumpShader_f(void)
1435 int i, language, mode, dupe;
1437 shadermodeinfo_t *modeinfo;
1440 for (language = 0;language < SHADERLANGUAGE_COUNT;language++)
1442 modeinfo = shadermodeinfo[language];
1443 for (mode = 0;mode < SHADERMODE_COUNT;mode++)
1445 // don't dump the same file multiple times (most or all shaders come from the same file)
1446 for (dupe = mode - 1;dupe >= 0;dupe--)
1447 if (!strcmp(modeinfo[mode].filename, modeinfo[dupe].filename))
1451 text = modeinfo[mode].builtinstring;
1454 file = FS_OpenRealFile(modeinfo[mode].filename, "w", false);
1457 FS_Print(file, "/* The engine may define the following macros:\n");
1458 FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
1459 for (i = 0;i < SHADERMODE_COUNT;i++)
1460 FS_Print(file, modeinfo[i].pretext);
1461 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1462 FS_Print(file, shaderpermutationinfo[i].pretext);
1463 FS_Print(file, "*/\n");
1464 FS_Print(file, text);
1466 Con_Printf("%s written\n", modeinfo[mode].filename);
1469 Con_Printf("failed to write to %s\n", modeinfo[mode].filename);
1474 void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemode, int rgbscale, qboolean usegamma, qboolean notrippy, qboolean suppresstexalpha)
1476 dpuint64 permutation = 0;
1477 if (r_trippy.integer && !notrippy)
1478 permutation |= SHADERPERMUTATION_TRIPPY;
1479 permutation |= SHADERPERMUTATION_VIEWTINT;
1481 permutation |= SHADERPERMUTATION_DIFFUSE;
1483 permutation |= SHADERPERMUTATION_SPECULAR;
1484 if (texturemode == GL_MODULATE)
1485 permutation |= SHADERPERMUTATION_COLORMAPPING;
1486 else if (texturemode == GL_ADD)
1487 permutation |= SHADERPERMUTATION_GLOW;
1488 else if (texturemode == GL_DECAL)
1489 permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1490 if (usegamma && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
1491 permutation |= SHADERPERMUTATION_GAMMARAMPS;
1492 if (suppresstexalpha)
1493 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1495 texturemode = GL_MODULATE;
1496 if (vid.allowalphatocoverage)
1497 GL_AlphaToCoverage(false);
1498 switch (vid.renderpath)
1500 case RENDERPATH_GL20:
1501 case RENDERPATH_GLES2:
1502 R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation);
1503 if (r_glsl_permutation->tex_Texture_First >= 0)
1504 R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , first );
1505 if (r_glsl_permutation->tex_Texture_Second >= 0)
1506 R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second, second);
1507 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0)
1508 R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps);
1513 void R_SetupShader_Generic_NoTexture(qboolean usegamma, qboolean notrippy)
1515 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, usegamma, notrippy, false);
1518 void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb, qboolean skeletal)
1520 dpuint64 permutation = 0;
1521 if (r_trippy.integer && !notrippy)
1522 permutation |= SHADERPERMUTATION_TRIPPY;
1524 permutation |= SHADERPERMUTATION_DEPTHRGB;
1526 permutation |= SHADERPERMUTATION_SKELETAL;
1528 if (vid.allowalphatocoverage)
1529 GL_AlphaToCoverage(false);
1530 switch (vid.renderpath)
1532 case RENDERPATH_GL20:
1533 case RENDERPATH_GLES2:
1534 R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
1535 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1536 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);
1542 #define BLENDFUNC_ALLOWS_COLORMOD 1
1543 #define BLENDFUNC_ALLOWS_FOG 2
1544 #define BLENDFUNC_ALLOWS_FOG_HACK0 4
1545 #define BLENDFUNC_ALLOWS_FOG_HACKALPHA 8
1546 #define BLENDFUNC_ALLOWS_ANYFOG (BLENDFUNC_ALLOWS_FOG | BLENDFUNC_ALLOWS_FOG_HACK0 | BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1547 static int R_BlendFuncFlags(int src, int dst)
1551 // a blendfunc allows colormod if:
1552 // a) it can never keep the destination pixel invariant, or
1553 // b) it can keep the destination pixel invariant, and still can do so if colormodded
1554 // this is to prevent unintended side effects from colormod
1556 // a blendfunc allows fog if:
1557 // blend(fog(src), fog(dst)) == fog(blend(src, dst))
1558 // this is to prevent unintended side effects from fog
1560 // these checks are the output of fogeval.pl
1562 r |= BLENDFUNC_ALLOWS_COLORMOD;
1563 if(src == GL_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1564 if(src == GL_DST_ALPHA && dst == GL_ONE_MINUS_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1565 if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1566 if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1567 if(src == GL_DST_COLOR && dst == GL_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1568 if(src == GL_DST_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1569 if(src == GL_DST_COLOR && dst == GL_ZERO) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1570 if(src == GL_ONE && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1571 if(src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG_HACKALPHA;
1572 if(src == GL_ONE && dst == GL_ZERO) r |= BLENDFUNC_ALLOWS_FOG;
1573 if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1574 if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1575 if(src == GL_ONE_MINUS_DST_COLOR && dst == GL_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1576 if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1577 if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1578 if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1579 if(src == GL_ONE_MINUS_SRC_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1580 if(src == GL_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1581 if(src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1582 if(src == GL_ZERO && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG;
1583 if(src == GL_ZERO && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1588 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)
1590 // select a permutation of the lighting shader appropriate to this
1591 // combination of texture, entity, light source, and fogging, only use the
1592 // minimum features necessary to avoid wasting rendering time in the
1593 // fragment shader on features that are not being used
1594 dpuint64 permutation = 0;
1595 unsigned int mode = 0;
1597 texture_t *t = rsurface.texture;
1599 matrix4x4_t tempmatrix;
1600 r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
1601 if (r_trippy.integer && !notrippy)
1602 permutation |= SHADERPERMUTATION_TRIPPY;
1603 if (t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1604 permutation |= SHADERPERMUTATION_ALPHAKILL;
1605 if (t->currentmaterialflags & MATERIALFLAG_OCCLUDE)
1606 permutation |= SHADERPERMUTATION_OCCLUDE;
1607 if (t->r_water_waterscroll[0] && t->r_water_waterscroll[1])
1608 permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
1609 if (rsurfacepass == RSURFPASS_BACKGROUND)
1611 // distorted background
1612 if (t->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1614 mode = SHADERMODE_WATER;
1615 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1616 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1617 if((r_wateralpha.value < 1) && (t->currentmaterialflags & MATERIALFLAG_WATERALPHA))
1619 // this is the right thing to do for wateralpha
1620 GL_BlendFunc(GL_ONE, GL_ZERO);
1621 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1625 // this is the right thing to do for entity alpha
1626 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1627 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1630 else if (t->currentmaterialflags & MATERIALFLAG_REFRACTION)
1632 mode = SHADERMODE_REFRACTION;
1633 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1634 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1635 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1636 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1640 mode = SHADERMODE_GENERIC;
1641 permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL;
1642 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1643 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1645 if (vid.allowalphatocoverage)
1646 GL_AlphaToCoverage(false);
1648 else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
1650 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1652 switch(t->offsetmapping)
1654 case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1655 case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1656 case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1657 case OFFSETMAPPING_OFF: break;
1660 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1661 permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1662 // normalmap (deferred prepass), may use alpha test on diffuse
1663 mode = SHADERMODE_DEFERREDGEOMETRY;
1664 GL_BlendFunc(GL_ONE, GL_ZERO);
1665 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1666 if (vid.allowalphatocoverage)
1667 GL_AlphaToCoverage(false);
1669 else if (rsurfacepass == RSURFPASS_RTLIGHT)
1671 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1673 switch(t->offsetmapping)
1675 case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1676 case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1677 case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1678 case OFFSETMAPPING_OFF: break;
1681 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1682 permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1683 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1684 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1686 mode = SHADERMODE_LIGHTSOURCE;
1687 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1688 permutation |= SHADERPERMUTATION_CUBEFILTER;
1689 if (VectorLength2(rtlightdiffuse) > 0)
1690 permutation |= SHADERPERMUTATION_DIFFUSE;
1691 if (VectorLength2(rtlightspecular) > 0)
1692 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1693 if (r_refdef.fogenabled)
1694 permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1695 if (t->colormapping)
1696 permutation |= SHADERPERMUTATION_COLORMAPPING;
1697 if (r_shadow_usingshadowmap2d)
1699 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1700 if(r_shadow_shadowmapvsdct)
1701 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
1703 if (r_shadow_shadowmap2ddepthbuffer)
1704 permutation |= SHADERPERMUTATION_DEPTHRGB;
1706 if (t->reflectmasktexture)
1707 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1708 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1709 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE);
1710 if (vid.allowalphatocoverage)
1711 GL_AlphaToCoverage(false);
1713 else if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
1715 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1717 switch(t->offsetmapping)
1719 case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1720 case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1721 case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1722 case OFFSETMAPPING_OFF: break;
1725 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1726 permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1727 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1728 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1729 // directional model lighting
1730 mode = SHADERMODE_LIGHTDIRECTION;
1731 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1732 permutation |= SHADERPERMUTATION_GLOW;
1733 if (VectorLength2(t->render_modellight_diffuse))
1734 permutation |= SHADERPERMUTATION_DIFFUSE;
1735 if (VectorLength2(t->render_modellight_specular) > 0)
1736 permutation |= SHADERPERMUTATION_SPECULAR;
1737 if (r_refdef.fogenabled)
1738 permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1739 if (t->colormapping)
1740 permutation |= SHADERPERMUTATION_COLORMAPPING;
1741 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1743 permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1744 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1746 if (r_shadow_shadowmap2ddepthbuffer)
1747 permutation |= SHADERPERMUTATION_DEPTHRGB;
1749 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1750 permutation |= SHADERPERMUTATION_REFLECTION;
1751 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1752 permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1753 if (t->reflectmasktexture)
1754 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1755 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld)
1757 permutation |= SHADERPERMUTATION_BOUNCEGRID;
1758 if (r_shadow_bouncegrid_state.directional)
1759 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1761 GL_BlendFunc(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1762 blendfuncflags = R_BlendFuncFlags(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1763 // when using alphatocoverage, we don't need alphakill
1764 if (vid.allowalphatocoverage)
1766 if (r_transparent_alphatocoverage.integer)
1768 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1769 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1772 GL_AlphaToCoverage(false);
1777 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1779 switch(t->offsetmapping)
1781 case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1782 case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1783 case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1784 case OFFSETMAPPING_OFF: break;
1787 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1788 permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1789 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1790 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1792 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1793 permutation |= SHADERPERMUTATION_GLOW;
1794 if (r_refdef.fogenabled)
1795 permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1796 if (t->colormapping)
1797 permutation |= SHADERPERMUTATION_COLORMAPPING;
1798 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1800 permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1801 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1803 if (r_shadow_shadowmap2ddepthbuffer)
1804 permutation |= SHADERPERMUTATION_DEPTHRGB;
1806 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1807 permutation |= SHADERPERMUTATION_REFLECTION;
1808 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1809 permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1810 if (t->reflectmasktexture)
1811 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1812 if (FAKELIGHT_ENABLED)
1814 // fake lightmapping (q1bsp, q3bsp, fullbright map)
1815 mode = SHADERMODE_FAKELIGHT;
1816 permutation |= SHADERPERMUTATION_DIFFUSE;
1817 if (VectorLength2(t->render_lightmap_specular) > 0)
1818 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1820 else if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
1822 // deluxemapping (light direction texture)
1823 if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace)
1824 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1826 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1827 permutation |= SHADERPERMUTATION_DIFFUSE;
1828 if (VectorLength2(t->render_lightmap_specular) > 0)
1829 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1831 else if (r_glsl_deluxemapping.integer >= 2)
1833 // fake deluxemapping (uniform light direction in tangentspace)
1834 if (rsurface.uselightmaptexture)
1835 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP;
1837 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR;
1838 permutation |= SHADERPERMUTATION_DIFFUSE;
1839 if (VectorLength2(t->render_lightmap_specular) > 0)
1840 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1842 else if (rsurface.uselightmaptexture)
1844 // ordinary lightmapping (q1bsp, q3bsp)
1845 mode = SHADERMODE_LIGHTMAP;
1849 // ordinary vertex coloring (q3bsp)
1850 mode = SHADERMODE_VERTEXCOLOR;
1852 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld)
1854 permutation |= SHADERPERMUTATION_BOUNCEGRID;
1855 if (r_shadow_bouncegrid_state.directional)
1856 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1858 GL_BlendFunc(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1859 blendfuncflags = R_BlendFuncFlags(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1860 // when using alphatocoverage, we don't need alphakill
1861 if (vid.allowalphatocoverage)
1863 if (r_transparent_alphatocoverage.integer)
1865 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1866 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1869 GL_AlphaToCoverage(false);
1872 if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG))
1873 permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE);
1874 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1875 permutation |= SHADERPERMUTATION_FOGALPHAHACK;
1876 switch(vid.renderpath)
1878 case RENDERPATH_GL20:
1879 case RENDERPATH_GLES2:
1880 if (!vid.useinterleavedarrays)
1882 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);
1883 R_Mesh_VertexPointer( 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
1884 R_Mesh_ColorPointer( 4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
1885 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
1886 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
1887 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
1888 R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
1889 R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
1890 R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
1891 R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
1892 R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
1896 RSurf_PrepareVerticesForBatch(BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | (rsurface.modellightmapcolor4f ? BATCHNEED_VERTEXMESH_VERTEXCOLOR : 0) | BATCHNEED_VERTEXMESH_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_VERTEXMESH_LIGHTMAP : 0) | (rsurface.entityskeletaltransform3x4 ? BATCHNEED_VERTEXMESH_SKELETAL : 0) | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
1897 R_Mesh_PrepareVertices_Mesh(rsurface.batchnumvertices, rsurface.batchvertexmesh, rsurface.batchvertexmesh_vertexbuffer, rsurface.batchvertexmesh_bufferoffset);
1899 // this has to be after RSurf_PrepareVerticesForBatch
1900 if (rsurface.batchskeletaltransform3x4buffer)
1901 permutation |= SHADERPERMUTATION_SKELETAL;
1902 R_SetupShader_SetPermutationGLSL(mode, permutation);
1903 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1904 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);
1906 if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
1907 if (mode == SHADERMODE_LIGHTSOURCE)
1909 if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
1910 if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1911 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1912 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
1913 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
1914 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
1916 // additive passes are only darkened by fog, not tinted
1917 if (r_glsl_permutation->loc_FogColor >= 0)
1918 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1919 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);
1923 if (mode == SHADERMODE_FLATCOLOR)
1925 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]);
1927 else if (mode == SHADERMODE_LIGHTDIRECTION)
1929 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]);
1930 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]);
1931 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]);
1932 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]);
1933 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]);
1934 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1935 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]);
1939 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]);
1940 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]);
1941 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]);
1942 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]);
1943 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]);
1945 // additive passes are only darkened by fog, not tinted
1946 if (r_glsl_permutation->loc_FogColor >= 0)
1948 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
1949 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1951 qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1953 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);
1954 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]);
1955 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]);
1956 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);
1957 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);
1958 if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, t->reflectmax - t->reflectmin);
1959 if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, t->reflectmin);
1960 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);
1961 if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
1963 if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
1964 if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
1965 if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
1966 if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
1968 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]);
1969 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]);
1973 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]);
1974 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]);
1977 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]);
1978 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));
1979 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
1980 if (r_glsl_permutation->loc_Color_Pants >= 0)
1982 if (t->pantstexture)
1983 qglUniform3f(r_glsl_permutation->loc_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
1985 qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
1987 if (r_glsl_permutation->loc_Color_Shirt >= 0)
1989 if (t->shirttexture)
1990 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
1992 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
1994 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]);
1995 if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
1996 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
1997 if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
1998 if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps,
1999 r_glsl_offsetmapping_scale.value*t->offsetscale,
2000 max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2001 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2002 max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
2004 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);
2005 if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, t->offsetbias);
2006 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]);
2007 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
2008 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);}
2009 if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
2011 if (r_glsl_permutation->tex_Texture_First >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , r_texture_white );
2012 if (r_glsl_permutation->tex_Texture_Second >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second , r_texture_white );
2013 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps , r_texture_gammaramps );
2014 if (r_glsl_permutation->tex_Texture_Normal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal , t->nmaptexture );
2015 if (r_glsl_permutation->tex_Texture_Color >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color , t->basetexture );
2016 if (r_glsl_permutation->tex_Texture_Gloss >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss , t->glosstexture );
2017 if (r_glsl_permutation->tex_Texture_Glow >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow , t->glowtexture );
2018 if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal , t->backgroundnmaptexture );
2019 if (r_glsl_permutation->tex_Texture_SecondaryColor >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor , t->backgroundbasetexture );
2020 if (r_glsl_permutation->tex_Texture_SecondaryGloss >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss , t->backgroundglosstexture );
2021 if (r_glsl_permutation->tex_Texture_SecondaryGlow >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow , t->backgroundglowtexture );
2022 if (r_glsl_permutation->tex_Texture_Pants >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants , t->pantstexture );
2023 if (r_glsl_permutation->tex_Texture_Shirt >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt , t->shirttexture );
2024 if (r_glsl_permutation->tex_Texture_ReflectMask >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask , t->reflectmasktexture );
2025 if (r_glsl_permutation->tex_Texture_ReflectCube >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
2026 if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture );
2027 if (r_glsl_permutation->tex_Texture_FogMask >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask , r_texture_fogattenuation );
2028 if (r_glsl_permutation->tex_Texture_Lightmap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
2029 if (r_glsl_permutation->tex_Texture_Deluxemap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Deluxemap , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap);
2030 if (r_glsl_permutation->tex_Texture_Attenuation >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation , r_shadow_attenuationgradienttexture );
2031 if (rsurfacepass == RSURFPASS_BACKGROUND)
2033 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);
2034 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);
2035 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);
2039 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);
2041 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap , r_shadow_prepassgeometrynormalmaptexture );
2042 if (r_glsl_permutation->tex_Texture_ScreenDiffuse >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse , r_shadow_prepasslightingdiffusetexture );
2043 if (r_glsl_permutation->tex_Texture_ScreenSpecular >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular , r_shadow_prepasslightingspeculartexture );
2044 if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
2046 if (r_glsl_permutation->tex_Texture_ShadowMap2D >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture );
2047 if (rsurface.rtlight)
2049 if (r_glsl_permutation->tex_Texture_Cube >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube , rsurface.rtlight->currentcubemap );
2050 if (r_glsl_permutation->tex_Texture_CubeProjection >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection , r_shadow_shadowmapvsdcttexture );
2053 if (r_glsl_permutation->tex_Texture_BounceGrid >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
2059 void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
2061 // select a permutation of the lighting shader appropriate to this
2062 // combination of texture, entity, light source, and fogging, only use the
2063 // minimum features necessary to avoid wasting rendering time in the
2064 // fragment shader on features that are not being used
2065 dpuint64 permutation = 0;
2066 unsigned int mode = 0;
2067 const float *lightcolorbase = rtlight->currentcolor;
2068 float ambientscale = rtlight->ambientscale;
2069 float diffusescale = rtlight->diffusescale;
2070 float specularscale = rtlight->specularscale;
2071 // this is the location of the light in view space
2072 vec3_t viewlightorigin;
2073 // this transforms from view space (camera) to light space (cubemap)
2074 matrix4x4_t viewtolight;
2075 matrix4x4_t lighttoview;
2076 float viewtolight16f[16];
2078 mode = SHADERMODE_DEFERREDLIGHTSOURCE;
2079 if (rtlight->currentcubemap != r_texture_whitecube)
2080 permutation |= SHADERPERMUTATION_CUBEFILTER;
2081 if (diffusescale > 0)
2082 permutation |= SHADERPERMUTATION_DIFFUSE;
2083 if (specularscale > 0 && r_shadow_gloss.integer > 0)
2084 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2085 if (r_shadow_usingshadowmap2d)
2087 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
2088 if (r_shadow_shadowmapvsdct)
2089 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
2091 if (r_shadow_shadowmap2ddepthbuffer)
2092 permutation |= SHADERPERMUTATION_DEPTHRGB;
2094 if (vid.allowalphatocoverage)
2095 GL_AlphaToCoverage(false);
2096 Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
2097 Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
2098 Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
2099 Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
2100 switch(vid.renderpath)
2102 case RENDERPATH_GL20:
2103 case RENDERPATH_GLES2:
2104 R_SetupShader_SetPermutationGLSL(mode, permutation);
2105 if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f( r_glsl_permutation->loc_LightPosition , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
2106 if (r_glsl_permutation->loc_ViewToLight >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight , 1, false, viewtolight16f);
2107 if (r_glsl_permutation->loc_DeferredColor_Ambient >= 0) qglUniform3f( r_glsl_permutation->loc_DeferredColor_Ambient , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
2108 if (r_glsl_permutation->loc_DeferredColor_Diffuse >= 0) qglUniform3f( r_glsl_permutation->loc_DeferredColor_Diffuse , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
2109 if (r_glsl_permutation->loc_DeferredColor_Specular >= 0) qglUniform3f( r_glsl_permutation->loc_DeferredColor_Specular , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
2110 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]);
2111 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]);
2112 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);
2113 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]);
2114 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f( r_glsl_permutation->loc_PixelToScreenTexCoord , 1.0f/vid.width, 1.0f/vid.height);
2116 if (r_glsl_permutation->tex_Texture_Attenuation >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation , r_shadow_attenuationgradienttexture );
2117 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap , r_shadow_prepassgeometrynormalmaptexture );
2118 if (r_glsl_permutation->tex_Texture_Cube >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube , rsurface.rtlight->currentcubemap );
2119 if (r_glsl_permutation->tex_Texture_ShadowMap2D >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D , r_shadow_shadowmap2ddepthtexture );
2120 if (r_glsl_permutation->tex_Texture_CubeProjection >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection , r_shadow_shadowmapvsdcttexture );
2125 #define SKINFRAME_HASH 1024
2129 unsigned int loadsequence; // incremented each level change
2130 memexpandablearray_t array;
2131 skinframe_t *hash[SKINFRAME_HASH];
2134 r_skinframe_t r_skinframe;
2136 void R_SkinFrame_PrepareForPurge(void)
2138 r_skinframe.loadsequence++;
2139 // wrap it without hitting zero
2140 if (r_skinframe.loadsequence >= 200)
2141 r_skinframe.loadsequence = 1;
2144 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
2148 // mark the skinframe as used for the purging code
2149 skinframe->loadsequence = r_skinframe.loadsequence;
2152 void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
2156 if (s->merged == s->base)
2158 R_PurgeTexture(s->stain); s->stain = NULL;
2159 R_PurgeTexture(s->merged); s->merged = NULL;
2160 R_PurgeTexture(s->base); s->base = NULL;
2161 R_PurgeTexture(s->pants); s->pants = NULL;
2162 R_PurgeTexture(s->shirt); s->shirt = NULL;
2163 R_PurgeTexture(s->nmap); s->nmap = NULL;
2164 R_PurgeTexture(s->gloss); s->gloss = NULL;
2165 R_PurgeTexture(s->glow); s->glow = NULL;
2166 R_PurgeTexture(s->fog); s->fog = NULL;
2167 R_PurgeTexture(s->reflect); s->reflect = NULL;
2168 s->loadsequence = 0;
2171 void R_SkinFrame_Purge(void)
2175 for (i = 0;i < SKINFRAME_HASH;i++)
2177 for (s = r_skinframe.hash[i];s;s = s->next)
2179 if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
2180 R_SkinFrame_PurgeSkinFrame(s);
2185 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
2187 char basename[MAX_QPATH];
2189 Image_StripImageExtension(name, basename, sizeof(basename));
2191 if( last == NULL ) {
2193 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2194 item = r_skinframe.hash[hashindex];
2199 // linearly search through the hash bucket
2200 for( ; item ; item = item->next ) {
2201 if( !strcmp( item->basename, basename ) ) {
2208 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add)
2212 char basename[MAX_QPATH];
2214 Image_StripImageExtension(name, basename, sizeof(basename));
2216 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2217 for (item = r_skinframe.hash[hashindex];item;item = item->next)
2218 if (!strcmp(item->basename, basename) && (comparecrc < 0 || (item->textureflags == textureflags && item->comparewidth == comparewidth && item->compareheight == compareheight && item->comparecrc == comparecrc)))
2225 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
2226 memset(item, 0, sizeof(*item));
2227 strlcpy(item->basename, basename, sizeof(item->basename));
2228 item->textureflags = textureflags & ~TEXF_FORCE_RELOAD;
2229 item->comparewidth = comparewidth;
2230 item->compareheight = compareheight;
2231 item->comparecrc = comparecrc;
2232 item->next = r_skinframe.hash[hashindex];
2233 r_skinframe.hash[hashindex] = item;
2235 else if (textureflags & TEXF_FORCE_RELOAD)
2239 R_SkinFrame_PurgeSkinFrame(item);
2242 R_SkinFrame_MarkUsed(item);
2246 #define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
2248 unsigned long long avgcolor[5], wsum; \
2256 for(pix = 0; pix < cnt; ++pix) \
2259 for(comp = 0; comp < 3; ++comp) \
2261 if(w) /* ignore perfectly black pixels because that is better for model skins */ \
2264 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2266 for(comp = 0; comp < 3; ++comp) \
2267 avgcolor[comp] += getpixel * w; \
2270 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2271 avgcolor[4] += getpixel; \
2273 if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
2275 skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
2276 skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
2277 skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
2278 skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
2281 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2283 skinframe_t *skinframe;
2285 if (cls.state == ca_dedicated)
2288 // return an existing skinframe if already loaded
2289 // if loading of the first image fails, don't make a new skinframe as it
2290 // would cause all future lookups of this to be missing
2291 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, -1, false);
2292 if (skinframe && skinframe->base)
2295 return R_SkinFrame_LoadExternal_SkinFrame(skinframe, name, textureflags, complain, fallbacknotexture);
2298 extern cvar_t gl_picmip;
2299 skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2302 unsigned char *pixels;
2303 unsigned char *bumppixels;
2304 unsigned char *basepixels = NULL;
2305 int basepixels_width = 0;
2306 int basepixels_height = 0;
2307 rtexture_t *ddsbase = NULL;
2308 qboolean ddshasalpha = false;
2309 float ddsavgcolor[4];
2310 char basename[MAX_QPATH];
2311 int miplevel = R_PicmipForFlags(textureflags);
2312 int savemiplevel = miplevel;
2316 if (cls.state == ca_dedicated)
2319 Image_StripImageExtension(name, basename, sizeof(basename));
2321 // check for DDS texture file first
2322 if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2324 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2325 if (basepixels == NULL && fallbacknotexture)
2326 basepixels = Image_GenerateNoTexture();
2327 if (basepixels == NULL)
2331 // FIXME handle miplevel
2333 if (developer_loading.integer)
2334 Con_Printf("loading skin \"%s\"\n", name);
2336 // we've got some pixels to store, so really allocate this new texture now
2338 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2339 textureflags &= ~TEXF_FORCE_RELOAD;
2340 skinframe->stain = NULL;
2341 skinframe->merged = NULL;
2342 skinframe->base = NULL;
2343 skinframe->pants = NULL;
2344 skinframe->shirt = NULL;
2345 skinframe->nmap = NULL;
2346 skinframe->gloss = NULL;
2347 skinframe->glow = NULL;
2348 skinframe->fog = NULL;
2349 skinframe->reflect = NULL;
2350 skinframe->hasalpha = false;
2351 // we could store the q2animname here too
2355 skinframe->base = ddsbase;
2356 skinframe->hasalpha = ddshasalpha;
2357 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2358 if (r_loadfog && skinframe->hasalpha)
2359 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);
2360 //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]);
2364 basepixels_width = image_width;
2365 basepixels_height = image_height;
2366 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);
2367 if (textureflags & TEXF_ALPHA)
2369 for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2371 if (basepixels[j] < 255)
2373 skinframe->hasalpha = true;
2377 if (r_loadfog && skinframe->hasalpha)
2379 // has transparent pixels
2380 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2381 for (j = 0;j < image_width * image_height * 4;j += 4)
2386 pixels[j+3] = basepixels[j+3];
2388 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);
2392 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2394 //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]);
2395 if (r_savedds && qglGetCompressedTexImageARB && skinframe->base)
2396 R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2397 if (r_savedds && qglGetCompressedTexImageARB && skinframe->fog)
2398 R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2404 mymiplevel = savemiplevel;
2405 if (r_loadnormalmap)
2406 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);
2407 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2409 skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2410 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2411 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2412 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2415 // _norm is the name used by tenebrae and has been adopted as standard
2416 if (r_loadnormalmap && skinframe->nmap == NULL)
2418 mymiplevel = savemiplevel;
2419 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2421 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);
2425 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2427 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2428 Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2429 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);
2431 Mem_Free(bumppixels);
2433 else if (r_shadow_bumpscale_basetexture.value > 0)
2435 pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2436 Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2437 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);
2441 if (r_savedds && qglGetCompressedTexImageARB && skinframe->nmap)
2442 R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2446 // _luma is supported only for tenebrae compatibility
2447 // _glow is the preferred name
2448 mymiplevel = savemiplevel;
2449 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))))
2451 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);
2453 if (r_savedds && qglGetCompressedTexImageARB && skinframe->glow)
2454 R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2456 Mem_Free(pixels);pixels = NULL;
2459 mymiplevel = savemiplevel;
2460 if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2462 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);
2464 if (r_savedds && qglGetCompressedTexImageARB && skinframe->gloss)
2465 R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2471 mymiplevel = savemiplevel;
2472 if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2474 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);
2476 if (r_savedds && qglGetCompressedTexImageARB && skinframe->pants)
2477 R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2483 mymiplevel = savemiplevel;
2484 if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2486 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);
2488 if (r_savedds && qglGetCompressedTexImageARB && skinframe->shirt)
2489 R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2495 mymiplevel = savemiplevel;
2496 if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2498 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);
2500 if (r_savedds && qglGetCompressedTexImageARB && skinframe->reflect)
2501 R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2508 Mem_Free(basepixels);
2513 // this is only used by .spr32 sprites, HL .spr files, HL .bsp files
2514 skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, qboolean sRGB)
2517 skinframe_t *skinframe;
2520 if (cls.state == ca_dedicated)
2523 // if already loaded just return it, otherwise make a new skinframe
2524 skinframe = R_SkinFrame_Find(name, textureflags, width, height, (!(textureflags & TEXF_FORCE_RELOAD) && skindata) ? CRC_Block(skindata, width*height*4) : -1, true);
2525 if (skinframe->base)
2527 textureflags &= ~TEXF_FORCE_RELOAD;
2529 skinframe->stain = NULL;
2530 skinframe->merged = NULL;
2531 skinframe->base = NULL;
2532 skinframe->pants = NULL;
2533 skinframe->shirt = NULL;
2534 skinframe->nmap = NULL;
2535 skinframe->gloss = NULL;
2536 skinframe->glow = NULL;
2537 skinframe->fog = NULL;
2538 skinframe->reflect = NULL;
2539 skinframe->hasalpha = false;
2541 // if no data was provided, then clearly the caller wanted to get a blank skinframe
2545 if (developer_loading.integer)
2546 Con_Printf("loading 32bit skin \"%s\"\n", name);
2548 if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2550 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2551 unsigned char *b = a + width * height * 4;
2552 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2553 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);
2556 skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2557 if (textureflags & TEXF_ALPHA)
2559 for (i = 3;i < width * height * 4;i += 4)
2561 if (skindata[i] < 255)
2563 skinframe->hasalpha = true;
2567 if (r_loadfog && skinframe->hasalpha)
2569 unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2570 memcpy(fogpixels, skindata, width * height * 4);
2571 for (i = 0;i < width * height * 4;i += 4)
2572 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2573 skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2574 Mem_Free(fogpixels);
2578 R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2579 //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]);
2584 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2588 skinframe_t *skinframe;
2590 if (cls.state == ca_dedicated)
2593 // if already loaded just return it, otherwise make a new skinframe
2594 skinframe = R_SkinFrame_Find(name, textureflags, width, height, (!(textureflags & TEXF_FORCE_RELOAD) && skindata) ? CRC_Block(skindata, width*height) : -1, true);
2595 if (skinframe->base)
2597 //textureflags &= ~TEXF_FORCE_RELOAD;
2599 skinframe->stain = NULL;
2600 skinframe->merged = NULL;
2601 skinframe->base = NULL;
2602 skinframe->pants = NULL;
2603 skinframe->shirt = NULL;
2604 skinframe->nmap = NULL;
2605 skinframe->gloss = NULL;
2606 skinframe->glow = NULL;
2607 skinframe->fog = NULL;
2608 skinframe->reflect = NULL;
2609 skinframe->hasalpha = false;
2611 // if no data was provided, then clearly the caller wanted to get a blank skinframe
2615 if (developer_loading.integer)
2616 Con_Printf("loading quake skin \"%s\"\n", name);
2618 // 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)
2619 skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2620 memcpy(skinframe->qpixels, skindata, width*height);
2621 skinframe->qwidth = width;
2622 skinframe->qheight = height;
2625 for (i = 0;i < width * height;i++)
2626 featuresmask |= palette_featureflags[skindata[i]];
2628 skinframe->hasalpha = false;
2631 skinframe->hasalpha = true;
2632 skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2633 skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2634 skinframe->qgeneratemerged = true;
2635 skinframe->qgeneratebase = skinframe->qhascolormapping;
2636 skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2638 R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2639 //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]);
2644 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboolean colormapped)
2648 unsigned char *skindata;
2651 if (!skinframe->qpixels)
2654 if (!skinframe->qhascolormapping)
2655 colormapped = false;
2659 if (!skinframe->qgeneratebase)
2664 if (!skinframe->qgeneratemerged)
2668 width = skinframe->qwidth;
2669 height = skinframe->qheight;
2670 skindata = skinframe->qpixels;
2672 if (skinframe->qgeneratenmap)
2674 unsigned char *a, *b;
2675 skinframe->qgeneratenmap = false;
2676 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2677 b = a + width * height * 4;
2678 // use either a custom palette or the quake palette
2679 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2680 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2681 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);
2685 if (skinframe->qgenerateglow)
2687 skinframe->qgenerateglow = false;
2688 if (skinframe->hasalpha) // fence textures
2689 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
2691 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
2696 skinframe->qgeneratebase = false;
2697 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);
2698 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);
2699 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);
2703 skinframe->qgeneratemerged = false;
2704 if (skinframe->hasalpha) // fence textures
2705 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);
2707 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);
2710 if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2712 Mem_Free(skinframe->qpixels);
2713 skinframe->qpixels = NULL;
2717 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)
2720 skinframe_t *skinframe;
2723 if (cls.state == ca_dedicated)
2726 // if already loaded just return it, otherwise make a new skinframe
2727 skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2728 if (skinframe->base)
2730 textureflags &= ~TEXF_FORCE_RELOAD;
2732 skinframe->stain = NULL;
2733 skinframe->merged = NULL;
2734 skinframe->base = NULL;
2735 skinframe->pants = NULL;
2736 skinframe->shirt = NULL;
2737 skinframe->nmap = NULL;
2738 skinframe->gloss = NULL;
2739 skinframe->glow = NULL;
2740 skinframe->fog = NULL;
2741 skinframe->reflect = NULL;
2742 skinframe->hasalpha = false;
2744 // if no data was provided, then clearly the caller wanted to get a blank skinframe
2748 if (developer_loading.integer)
2749 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2751 skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2752 if ((textureflags & TEXF_ALPHA) && alphapalette)
2754 for (i = 0;i < width * height;i++)
2756 if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2758 skinframe->hasalpha = true;
2762 if (r_loadfog && skinframe->hasalpha)
2763 skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2766 R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2767 //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]);
2772 skinframe_t *R_SkinFrame_LoadMissing(void)
2774 skinframe_t *skinframe;
2776 if (cls.state == ca_dedicated)
2779 skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2780 skinframe->stain = NULL;
2781 skinframe->merged = NULL;
2782 skinframe->base = NULL;
2783 skinframe->pants = NULL;
2784 skinframe->shirt = NULL;
2785 skinframe->nmap = NULL;
2786 skinframe->gloss = NULL;
2787 skinframe->glow = NULL;
2788 skinframe->fog = NULL;
2789 skinframe->reflect = NULL;
2790 skinframe->hasalpha = false;
2792 skinframe->avgcolor[0] = rand() / RAND_MAX;
2793 skinframe->avgcolor[1] = rand() / RAND_MAX;
2794 skinframe->avgcolor[2] = rand() / RAND_MAX;
2795 skinframe->avgcolor[3] = 1;
2800 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2803 static unsigned char pix[16][16][4];
2805 if (cls.state == ca_dedicated)
2808 // this makes a light grey/dark grey checkerboard texture
2811 for (y = 0; y < 16; y++)
2813 for (x = 0; x < 16; x++)
2815 if ((y < 8) ^ (x < 8))
2833 return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, pix[0][0], 16, 16, false);
2836 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qboolean sRGB)
2838 skinframe_t *skinframe;
2839 if (cls.state == ca_dedicated)
2841 // if already loaded just return it, otherwise make a new skinframe
2842 skinframe = R_SkinFrame_Find(name, textureflags, width, height, (textureflags & TEXF_FORCE_RELOAD) ? -1 : 0, true);
2843 if (skinframe->base)
2845 textureflags &= ~TEXF_FORCE_RELOAD;
2846 skinframe->stain = NULL;
2847 skinframe->merged = NULL;
2848 skinframe->base = NULL;
2849 skinframe->pants = NULL;
2850 skinframe->shirt = NULL;
2851 skinframe->nmap = NULL;
2852 skinframe->gloss = NULL;
2853 skinframe->glow = NULL;
2854 skinframe->fog = NULL;
2855 skinframe->reflect = NULL;
2856 skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2857 // if no data was provided, then clearly the caller wanted to get a blank skinframe
2860 if (developer_loading.integer)
2861 Con_Printf("loading 32bit skin \"%s\"\n", name);
2862 skinframe->base = skinframe->merged = tex;
2863 Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2867 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2868 typedef struct suffixinfo_s
2871 qboolean flipx, flipy, flipdiagonal;
2874 static suffixinfo_t suffix[3][6] =
2877 {"px", false, false, false},
2878 {"nx", false, false, false},
2879 {"py", false, false, false},
2880 {"ny", false, false, false},
2881 {"pz", false, false, false},
2882 {"nz", false, false, false}
2885 {"posx", false, false, false},
2886 {"negx", false, false, false},
2887 {"posy", false, false, false},
2888 {"negy", false, false, false},
2889 {"posz", false, false, false},
2890 {"negz", false, false, false}
2893 {"rt", true, false, true},
2894 {"lf", false, true, true},
2895 {"ft", true, true, false},
2896 {"bk", false, false, false},
2897 {"up", true, false, true},
2898 {"dn", true, false, true}
2902 static int componentorder[4] = {0, 1, 2, 3};
2904 static rtexture_t *R_LoadCubemap(const char *basename)
2906 int i, j, cubemapsize;
2907 unsigned char *cubemappixels, *image_buffer;
2908 rtexture_t *cubemaptexture;
2910 // must start 0 so the first loadimagepixels has no requested width/height
2912 cubemappixels = NULL;
2913 cubemaptexture = NULL;
2914 // keep trying different suffix groups (posx, px, rt) until one loads
2915 for (j = 0;j < 3 && !cubemappixels;j++)
2917 // load the 6 images in the suffix group
2918 for (i = 0;i < 6;i++)
2920 // generate an image name based on the base and and suffix
2921 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2923 if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
2925 // an image loaded, make sure width and height are equal
2926 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
2928 // if this is the first image to load successfully, allocate the cubemap memory
2929 if (!cubemappixels && image_width >= 1)
2931 cubemapsize = image_width;
2932 // note this clears to black, so unavailable sides are black
2933 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2935 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2937 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);
2940 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2942 Mem_Free(image_buffer);
2946 // if a cubemap loaded, upload it
2949 if (developer_loading.integer)
2950 Con_Printf("loading cubemap \"%s\"\n", basename);
2952 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);
2953 Mem_Free(cubemappixels);
2957 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
2958 if (developer_loading.integer)
2960 Con_Printf("(tried tried images ");
2961 for (j = 0;j < 3;j++)
2962 for (i = 0;i < 6;i++)
2963 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2964 Con_Print(" and was unable to find any of them).\n");
2967 return cubemaptexture;
2970 rtexture_t *R_GetCubemap(const char *basename)
2973 for (i = 0;i < r_texture_numcubemaps;i++)
2974 if (r_texture_cubemaps[i] != NULL)
2975 if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
2976 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
2977 if (i >= MAX_CUBEMAPS || !r_main_mempool)
2978 return r_texture_whitecube;
2979 r_texture_numcubemaps++;
2980 r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
2981 strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
2982 r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
2983 return r_texture_cubemaps[i]->texture;
2986 static void R_Main_FreeViewCache(void)
2988 if (r_refdef.viewcache.entityvisible)
2989 Mem_Free(r_refdef.viewcache.entityvisible);
2990 if (r_refdef.viewcache.world_pvsbits)
2991 Mem_Free(r_refdef.viewcache.world_pvsbits);
2992 if (r_refdef.viewcache.world_leafvisible)
2993 Mem_Free(r_refdef.viewcache.world_leafvisible);
2994 if (r_refdef.viewcache.world_surfacevisible)
2995 Mem_Free(r_refdef.viewcache.world_surfacevisible);
2996 memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
2999 static void R_Main_ResizeViewCache(void)
3001 int numentities = r_refdef.scene.numentities;
3002 int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
3003 int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
3004 int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
3005 int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
3006 if (r_refdef.viewcache.maxentities < numentities)
3008 r_refdef.viewcache.maxentities = numentities;
3009 if (r_refdef.viewcache.entityvisible)
3010 Mem_Free(r_refdef.viewcache.entityvisible);
3011 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
3013 if (r_refdef.viewcache.world_numclusters != numclusters)
3015 r_refdef.viewcache.world_numclusters = numclusters;
3016 r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
3017 if (r_refdef.viewcache.world_pvsbits)
3018 Mem_Free(r_refdef.viewcache.world_pvsbits);
3019 r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
3021 if (r_refdef.viewcache.world_numleafs != numleafs)
3023 r_refdef.viewcache.world_numleafs = numleafs;
3024 if (r_refdef.viewcache.world_leafvisible)
3025 Mem_Free(r_refdef.viewcache.world_leafvisible);
3026 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
3028 if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
3030 r_refdef.viewcache.world_numsurfaces = numsurfaces;
3031 if (r_refdef.viewcache.world_surfacevisible)
3032 Mem_Free(r_refdef.viewcache.world_surfacevisible);
3033 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
3037 extern rtexture_t *loadingscreentexture;
3038 static void gl_main_start(void)
3040 loadingscreentexture = NULL;
3041 r_texture_blanknormalmap = NULL;
3042 r_texture_white = NULL;
3043 r_texture_grey128 = NULL;
3044 r_texture_black = NULL;
3045 r_texture_whitecube = NULL;
3046 r_texture_normalizationcube = NULL;
3047 r_texture_fogattenuation = NULL;
3048 r_texture_fogheighttexture = NULL;
3049 r_texture_gammaramps = NULL;
3050 r_texture_numcubemaps = 0;
3051 r_uniformbufferalignment = 32;
3053 r_loaddds = r_texture_dds_load.integer != 0;
3054 r_savedds = vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3056 switch(vid.renderpath)
3058 case RENDERPATH_GL20:
3059 case RENDERPATH_GLES2:
3060 Cvar_SetValueQuick(&r_textureunits, vid.texunits);
3061 Cvar_SetValueQuick(&gl_combine, 1);
3062 Cvar_SetValueQuick(&r_glsl, 1);
3063 r_loadnormalmap = true;
3066 #ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
3067 if (vid.support.arb_uniform_buffer_object)
3068 qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
3074 R_FrameData_Reset();
3075 R_BufferData_Reset();
3079 memset(r_queries, 0, sizeof(r_queries));
3081 r_qwskincache = NULL;
3082 r_qwskincache_size = 0;
3084 // due to caching of texture_t references, the collision cache must be reset
3085 Collision_Cache_Reset(true);
3087 // set up r_skinframe loading system for textures
3088 memset(&r_skinframe, 0, sizeof(r_skinframe));
3089 r_skinframe.loadsequence = 1;
3090 Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
3092 r_main_texturepool = R_AllocTexturePool();
3093 R_BuildBlankTextures();
3095 if (vid.support.arb_texture_cube_map)
3098 R_BuildNormalizationCube();
3100 r_texture_fogattenuation = NULL;
3101 r_texture_fogheighttexture = NULL;
3102 r_texture_gammaramps = NULL;
3103 //r_texture_fogintensity = NULL;
3104 memset(&r_fb, 0, sizeof(r_fb));
3105 Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
3106 r_glsl_permutation = NULL;
3107 memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3108 Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
3109 memset(&r_svbsp, 0, sizeof (r_svbsp));
3111 memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
3112 r_texture_numcubemaps = 0;
3114 r_refdef.fogmasktable_density = 0;
3117 // For Steelstorm Android
3118 // FIXME CACHE the program and reload
3119 // FIXME see possible combinations for SS:BR android
3120 Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
3121 R_SetupShader_SetPermutationGLSL(0, 12);
3122 R_SetupShader_SetPermutationGLSL(0, 13);
3123 R_SetupShader_SetPermutationGLSL(0, 8388621);
3124 R_SetupShader_SetPermutationGLSL(3, 0);
3125 R_SetupShader_SetPermutationGLSL(3, 2048);
3126 R_SetupShader_SetPermutationGLSL(5, 0);
3127 R_SetupShader_SetPermutationGLSL(5, 2);
3128 R_SetupShader_SetPermutationGLSL(5, 2048);
3129 R_SetupShader_SetPermutationGLSL(5, 8388608);
3130 R_SetupShader_SetPermutationGLSL(11, 1);
3131 R_SetupShader_SetPermutationGLSL(11, 2049);
3132 R_SetupShader_SetPermutationGLSL(11, 8193);
3133 R_SetupShader_SetPermutationGLSL(11, 10241);
3134 Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
3138 static void gl_main_shutdown(void)
3140 R_RenderTarget_FreeUnused(true);
3141 Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
3143 R_FrameData_Reset();
3144 R_BufferData_Reset();
3146 R_Main_FreeViewCache();
3148 switch(vid.renderpath)
3150 case RENDERPATH_GL20:
3151 case RENDERPATH_GLES2:
3152 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
3154 qglDeleteQueriesARB(r_maxqueries, r_queries);
3161 memset(r_queries, 0, sizeof(r_queries));
3163 r_qwskincache = NULL;
3164 r_qwskincache_size = 0;
3166 // clear out the r_skinframe state
3167 Mem_ExpandableArray_FreeArray(&r_skinframe.array);
3168 memset(&r_skinframe, 0, sizeof(r_skinframe));
3171 Mem_Free(r_svbsp.nodes);
3172 memset(&r_svbsp, 0, sizeof (r_svbsp));
3173 R_FreeTexturePool(&r_main_texturepool);
3174 loadingscreentexture = NULL;
3175 r_texture_blanknormalmap = NULL;
3176 r_texture_white = NULL;
3177 r_texture_grey128 = NULL;
3178 r_texture_black = NULL;
3179 r_texture_whitecube = NULL;
3180 r_texture_normalizationcube = NULL;
3181 r_texture_fogattenuation = NULL;
3182 r_texture_fogheighttexture = NULL;
3183 r_texture_gammaramps = NULL;
3184 r_texture_numcubemaps = 0;
3185 //r_texture_fogintensity = NULL;
3186 memset(&r_fb, 0, sizeof(r_fb));
3189 r_glsl_permutation = NULL;
3190 memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3191 Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
3194 static void gl_main_newmap(void)
3196 // FIXME: move this code to client
3197 char *entities, entname[MAX_QPATH];
3199 Mem_Free(r_qwskincache);
3200 r_qwskincache = NULL;
3201 r_qwskincache_size = 0;
3204 dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension);
3205 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
3207 CL_ParseEntityLump(entities);
3211 if (cl.worldmodel->brush.entities)
3212 CL_ParseEntityLump(cl.worldmodel->brush.entities);
3214 R_Main_FreeViewCache();
3216 R_FrameData_Reset();
3217 R_BufferData_Reset();
3220 void GL_Main_Init(void)
3223 r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
3224 R_InitShaderModeInfo();
3226 Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
3227 Cmd_AddCommand("r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
3228 // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
3229 if (gamemode == GAME_NEHAHRA)
3231 Cvar_RegisterVariable (&gl_fogenable);
3232 Cvar_RegisterVariable (&gl_fogdensity);
3233 Cvar_RegisterVariable (&gl_fogred);
3234 Cvar_RegisterVariable (&gl_foggreen);
3235 Cvar_RegisterVariable (&gl_fogblue);
3236 Cvar_RegisterVariable (&gl_fogstart);
3237 Cvar_RegisterVariable (&gl_fogend);
3238 Cvar_RegisterVariable (&gl_skyclip);
3240 Cvar_RegisterVariable(&r_motionblur);
3241 Cvar_RegisterVariable(&r_damageblur);
3242 Cvar_RegisterVariable(&r_motionblur_averaging);
3243 Cvar_RegisterVariable(&r_motionblur_randomize);
3244 Cvar_RegisterVariable(&r_motionblur_minblur);
3245 Cvar_RegisterVariable(&r_motionblur_maxblur);
3246 Cvar_RegisterVariable(&r_motionblur_velocityfactor);
3247 Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed);
3248 Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed);
3249 Cvar_RegisterVariable(&r_motionblur_mousefactor);
3250 Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed);
3251 Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed);
3252 Cvar_RegisterVariable(&r_equalize_entities_fullbright);
3253 Cvar_RegisterVariable(&r_equalize_entities_minambient);
3254 Cvar_RegisterVariable(&r_equalize_entities_by);
3255 Cvar_RegisterVariable(&r_equalize_entities_to);
3256 Cvar_RegisterVariable(&r_depthfirst);
3257 Cvar_RegisterVariable(&r_useinfinitefarclip);
3258 Cvar_RegisterVariable(&r_farclip_base);
3259 Cvar_RegisterVariable(&r_farclip_world);
3260 Cvar_RegisterVariable(&r_nearclip);
3261 Cvar_RegisterVariable(&r_deformvertexes);
3262 Cvar_RegisterVariable(&r_transparent);
3263 Cvar_RegisterVariable(&r_transparent_alphatocoverage);
3264 Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
3265 Cvar_RegisterVariable(&r_transparent_useplanardistance);
3266 Cvar_RegisterVariable(&r_showoverdraw);
3267 Cvar_RegisterVariable(&r_showbboxes);
3268 Cvar_RegisterVariable(&r_showbboxes_client);
3269 Cvar_RegisterVariable(&r_showsurfaces);
3270 Cvar_RegisterVariable(&r_showtris);
3271 Cvar_RegisterVariable(&r_shownormals);
3272 Cvar_RegisterVariable(&r_showlighting);
3273 Cvar_RegisterVariable(&r_showshadowvolumes);
3274 Cvar_RegisterVariable(&r_showcollisionbrushes);
3275 Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
3276 Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
3277 Cvar_RegisterVariable(&r_showdisabledepthtest);
3278 Cvar_RegisterVariable(&r_showspriteedges);
3279 Cvar_RegisterVariable(&r_showparticleedges);
3280 Cvar_RegisterVariable(&r_drawportals);
3281 Cvar_RegisterVariable(&r_drawentities);
3282 Cvar_RegisterVariable(&r_draw2d);
3283 Cvar_RegisterVariable(&r_drawworld);
3284 Cvar_RegisterVariable(&r_cullentities_trace);
3285 Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
3286 Cvar_RegisterVariable(&r_cullentities_trace_samples);
3287 Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
3288 Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
3289 Cvar_RegisterVariable(&r_cullentities_trace_expand);
3290 Cvar_RegisterVariable(&r_cullentities_trace_pad);
3291 Cvar_RegisterVariable(&r_cullentities_trace_delay);
3292 Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
3293 Cvar_RegisterVariable(&r_sortentities);
3294 Cvar_RegisterVariable(&r_drawviewmodel);
3295 Cvar_RegisterVariable(&r_drawexteriormodel);
3296 Cvar_RegisterVariable(&r_speeds);
3297 Cvar_RegisterVariable(&r_fullbrights);
3298 Cvar_RegisterVariable(&r_wateralpha);
3299 Cvar_RegisterVariable(&r_dynamic);
3300 Cvar_RegisterVariable(&r_fakelight);
3301 Cvar_RegisterVariable(&r_fakelight_intensity);
3302 Cvar_RegisterVariable(&r_fullbright_directed);
3303 Cvar_RegisterVariable(&r_fullbright_directed_ambient);
3304 Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
3305 Cvar_RegisterVariable(&r_fullbright_directed_pitch);
3306 Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
3307 Cvar_RegisterVariable(&r_fullbright);
3308 Cvar_RegisterVariable(&r_shadows);
3309 Cvar_RegisterVariable(&r_shadows_darken);
3310 Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
3311 Cvar_RegisterVariable(&r_shadows_castfrombmodels);
3312 Cvar_RegisterVariable(&r_shadows_throwdistance);
3313 Cvar_RegisterVariable(&r_shadows_throwdirection);
3314 Cvar_RegisterVariable(&r_shadows_focus);
3315 Cvar_RegisterVariable(&r_shadows_shadowmapscale);
3316 Cvar_RegisterVariable(&r_shadows_shadowmapbias);
3317 Cvar_RegisterVariable(&r_q1bsp_skymasking);
3318 Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
3319 Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
3320 Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
3321 Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
3322 Cvar_RegisterVariable(&r_fog_exp2);
3323 Cvar_RegisterVariable(&r_fog_clear);
3324 Cvar_RegisterVariable(&r_drawfog);
3325 Cvar_RegisterVariable(&r_transparentdepthmasking);
3326 Cvar_RegisterVariable(&r_transparent_sortmindist);
3327 Cvar_RegisterVariable(&r_transparent_sortmaxdist);
3328 Cvar_RegisterVariable(&r_transparent_sortarraysize);
3329 Cvar_RegisterVariable(&r_texture_dds_load);
3330 Cvar_RegisterVariable(&r_texture_dds_save);
3331 Cvar_RegisterVariable(&r_textureunits);
3332 Cvar_RegisterVariable(&gl_combine);
3333 Cvar_RegisterVariable(&r_usedepthtextures);
3334 Cvar_RegisterVariable(&r_viewfbo);
3335 Cvar_RegisterVariable(&r_rendertarget_debug);
3336 Cvar_RegisterVariable(&r_viewscale);
3337 Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3338 Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3339 Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3340 Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3341 Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3342 Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3343 Cvar_RegisterVariable(&r_glsl);
3344 Cvar_RegisterVariable(&r_glsl_deluxemapping);
3345 Cvar_RegisterVariable(&r_glsl_offsetmapping);
3346 Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3347 Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3348 Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3349 Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3350 Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3351 Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3352 Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3353 Cvar_RegisterVariable(&r_glsl_postprocess);
3354 Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3355 Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3356 Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3357 Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3358 Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3359 Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3360 Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3361 Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3362 Cvar_RegisterVariable(&r_celshading);
3363 Cvar_RegisterVariable(&r_celoutlines);
3365 Cvar_RegisterVariable(&r_water);
3366 Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3367 Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3368 Cvar_RegisterVariable(&r_water_clippingplanebias);
3369 Cvar_RegisterVariable(&r_water_refractdistort);
3370 Cvar_RegisterVariable(&r_water_reflectdistort);
3371 Cvar_RegisterVariable(&r_water_scissormode);
3372 Cvar_RegisterVariable(&r_water_lowquality);
3373 Cvar_RegisterVariable(&r_water_hideplayer);
3375 Cvar_RegisterVariable(&r_lerpsprites);
3376 Cvar_RegisterVariable(&r_lerpmodels);
3377 Cvar_RegisterVariable(&r_lerplightstyles);
3378 Cvar_RegisterVariable(&r_waterscroll);
3379 Cvar_RegisterVariable(&r_bloom);
3380 Cvar_RegisterVariable(&r_bloom_colorscale);
3381 Cvar_RegisterVariable(&r_bloom_brighten);
3382 Cvar_RegisterVariable(&r_bloom_blur);
3383 Cvar_RegisterVariable(&r_bloom_resolution);
3384 Cvar_RegisterVariable(&r_bloom_colorexponent);
3385 Cvar_RegisterVariable(&r_bloom_colorsubtract);
3386 Cvar_RegisterVariable(&r_bloom_scenebrightness);
3387 Cvar_RegisterVariable(&r_hdr_scenebrightness);
3388 Cvar_RegisterVariable(&r_hdr_glowintensity);
3389 Cvar_RegisterVariable(&r_hdr_irisadaptation);
3390 Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3391 Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3392 Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3393 Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3394 Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3395 Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3396 Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3397 Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3398 Cvar_RegisterVariable(&developer_texturelogging);
3399 Cvar_RegisterVariable(&gl_lightmaps);
3400 Cvar_RegisterVariable(&r_test);
3401 Cvar_RegisterVariable(&r_batch_multidraw);
3402 Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3403 Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3404 Cvar_RegisterVariable(&r_glsl_skeletal);
3405 Cvar_RegisterVariable(&r_glsl_saturation);
3406 Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3407 Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3408 Cvar_RegisterVariable(&r_framedatasize);
3409 for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3410 Cvar_RegisterVariable(&r_buffermegs[i]);
3411 Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3412 if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3413 Cvar_SetValue("r_fullbrights", 0);
3414 #ifdef DP_MOBILETOUCH
3415 // GLES devices have terrible depth precision in general, so...
3416 Cvar_SetValueQuick(&r_nearclip, 4);
3417 Cvar_SetValueQuick(&r_farclip_base, 4096);
3418 Cvar_SetValueQuick(&r_farclip_world, 0);
3419 Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3421 R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3424 void Render_Init(void)
3437 R_LightningBeams_Init();
3447 extern char *ENGINE_EXTENSIONS;
3450 gl_renderer = (const char *)qglGetString(GL_RENDERER);
3451 gl_vendor = (const char *)qglGetString(GL_VENDOR);
3452 gl_version = (const char *)qglGetString(GL_VERSION);
3453 gl_extensions = (const char *)qglGetString(GL_EXTENSIONS);
3457 if (!gl_platformextensions)
3458 gl_platformextensions = "";
3460 Con_Printf("GL_VENDOR: %s\n", gl_vendor);
3461 Con_Printf("GL_RENDERER: %s\n", gl_renderer);
3462 Con_Printf("GL_VERSION: %s\n", gl_version);
3463 Con_DPrintf("GL_EXTENSIONS: %s\n", gl_extensions);
3464 Con_DPrintf("%s_EXTENSIONS: %s\n", gl_platform, gl_platformextensions);
3466 VID_CheckExtensions();
3468 // LordHavoc: report supported extensions
3470 Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions );
3472 Con_DPrintf("\nQuakeC extensions for server and client: %s\n", vm_sv_extensions );
3475 // clear to black (loading plaque will be seen over this)
3476 GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128);
3480 int R_CullBox(const vec3_t mins, const vec3_t maxs)
3484 if (r_trippy.integer)
3486 for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
3488 p = r_refdef.view.frustum + i;
3493 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3497 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3501 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3505 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3509 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3513 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3517 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3521 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3529 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3533 if (r_trippy.integer)
3535 for (i = 0;i < numplanes;i++)
3542 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3546 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3550 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3554 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3558 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3562 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3566 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3570 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3578 //==================================================================================
3580 // LordHavoc: this stores temporary data used within the same frame
3582 typedef struct r_framedata_mem_s
3584 struct r_framedata_mem_s *purge; // older mem block to free on next frame
3585 size_t size; // how much usable space
3586 size_t current; // how much space in use
3587 size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3588 size_t wantedsize; // how much space was allocated
3589 unsigned char *data; // start of real data (16byte aligned)
3593 static r_framedata_mem_t *r_framedata_mem;
3595 void R_FrameData_Reset(void)
3597 while (r_framedata_mem)
3599 r_framedata_mem_t *next = r_framedata_mem->purge;
3600 Mem_Free(r_framedata_mem);
3601 r_framedata_mem = next;
3605 static void R_FrameData_Resize(qboolean mustgrow)
3608 wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3609 wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3610 if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3612 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3613 newmem->wantedsize = wantedsize;
3614 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3615 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3616 newmem->current = 0;
3618 newmem->purge = r_framedata_mem;
3619 r_framedata_mem = newmem;
3623 void R_FrameData_NewFrame(void)
3625 R_FrameData_Resize(false);
3626 if (!r_framedata_mem)
3628 // if we ran out of space on the last frame, free the old memory now
3629 while (r_framedata_mem->purge)
3631 // repeatedly remove the second item in the list, leaving only head
3632 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3633 Mem_Free(r_framedata_mem->purge);
3634 r_framedata_mem->purge = next;
3636 // reset the current mem pointer
3637 r_framedata_mem->current = 0;
3638 r_framedata_mem->mark = 0;
3641 void *R_FrameData_Alloc(size_t size)
3646 // align to 16 byte boundary - the data pointer is already aligned, so we
3647 // only need to ensure the size of every allocation is also aligned
3648 size = (size + 15) & ~15;
3650 while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3652 // emergency - we ran out of space, allocate more memory
3653 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3654 newvalue = r_framedatasize.value * 2.0f;
3655 // 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
3656 if (sizeof(size_t) >= 8)
3657 newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3659 newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3660 // this might not be a growing it, but we'll allocate another buffer every time
3661 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3662 R_FrameData_Resize(true);
3665 data = r_framedata_mem->data + r_framedata_mem->current;
3666 r_framedata_mem->current += size;
3668 // count the usage for stats
3669 r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3670 r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3672 return (void *)data;
3675 void *R_FrameData_Store(size_t size, void *data)
3677 void *d = R_FrameData_Alloc(size);
3679 memcpy(d, data, size);
3683 void R_FrameData_SetMark(void)
3685 if (!r_framedata_mem)
3687 r_framedata_mem->mark = r_framedata_mem->current;
3690 void R_FrameData_ReturnToMark(void)
3692 if (!r_framedata_mem)
3694 r_framedata_mem->current = r_framedata_mem->mark;
3697 //==================================================================================
3699 // avoid reusing the same buffer objects on consecutive frames
3700 #define R_BUFFERDATA_CYCLE 3
3702 typedef struct r_bufferdata_buffer_s
3704 struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3705 size_t size; // how much usable space
3706 size_t current; // how much space in use
3707 r_meshbuffer_t *buffer; // the buffer itself
3709 r_bufferdata_buffer_t;
3711 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3712 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3714 /// frees all dynamic buffers
3715 void R_BufferData_Reset(void)
3718 r_bufferdata_buffer_t **p, *mem;
3719 for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3721 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3724 p = &r_bufferdata_buffer[cycle][type];
3730 R_Mesh_DestroyMeshBuffer(mem->buffer);
3737 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3738 static void R_BufferData_Resize(r_bufferdata_type_t type, qboolean mustgrow, size_t minsize)
3740 r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3742 float newvalue = r_buffermegs[type].value;
3744 // increase the cvar if we have to (but only if we already have a mem)
3745 if (mustgrow && mem)
3747 newvalue = bound(0.25f, newvalue, 256.0f);
3748 while (newvalue * 1024*1024 < minsize)
3751 // clamp the cvar to valid range
3752 newvalue = bound(0.25f, newvalue, 256.0f);
3753 if (r_buffermegs[type].value != newvalue)
3754 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3756 // calculate size in bytes
3757 size = (size_t)(newvalue * 1024*1024);
3758 size = bound(131072, size, 256*1024*1024);
3760 // allocate a new buffer if the size is different (purge old one later)
3761 // or if we were told we must grow the buffer
3762 if (!mem || mem->size != size || mustgrow)
3764 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3767 if (type == R_BUFFERDATA_VERTEX)
3768 mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3769 else if (type == R_BUFFERDATA_INDEX16)
3770 mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3771 else if (type == R_BUFFERDATA_INDEX32)
3772 mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3773 else if (type == R_BUFFERDATA_UNIFORM)
3774 mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3775 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3776 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3780 void R_BufferData_NewFrame(void)
3783 r_bufferdata_buffer_t **p, *mem;
3784 // cycle to the next frame's buffers
3785 r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3786 // if we ran out of space on the last time we used these buffers, free the old memory now
3787 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3789 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3791 R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3792 // free all but the head buffer, this is how we recycle obsolete
3793 // buffers after they are no longer in use
3794 p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3800 R_Mesh_DestroyMeshBuffer(mem->buffer);
3803 // reset the current offset
3804 r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3809 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3811 r_bufferdata_buffer_t *mem;
3815 *returnbufferoffset = 0;
3817 // align size to a byte boundary appropriate for the buffer type, this
3818 // makes all allocations have aligned start offsets
3819 if (type == R_BUFFERDATA_UNIFORM)
3820 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3822 padsize = (datasize + 15) & ~15;
3824 // if we ran out of space in this buffer we must allocate a new one
3825 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)
3826 R_BufferData_Resize(type, true, padsize);
3828 // if the resize did not give us enough memory, fail
3829 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)
3830 Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3832 mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3833 offset = (int)mem->current;
3834 mem->current += padsize;
3836 // upload the data to the buffer at the chosen offset
3838 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3839 R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3841 // count the usage for stats
3842 r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3843 r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3845 // return the buffer offset
3846 *returnbufferoffset = offset;
3851 //==================================================================================
3853 // LordHavoc: animcache originally written by Echon, rewritten since then
3856 * Animation cache prevents re-generating mesh data for an animated model
3857 * multiple times in one frame for lighting, shadowing, reflections, etc.
3860 void R_AnimCache_Free(void)
3864 void R_AnimCache_ClearCache(void)
3867 entity_render_t *ent;
3869 for (i = 0;i < r_refdef.scene.numentities;i++)
3871 ent = r_refdef.scene.entities[i];
3872 ent->animcache_vertex3f = NULL;
3873 ent->animcache_vertex3f_vertexbuffer = NULL;
3874 ent->animcache_vertex3f_bufferoffset = 0;
3875 ent->animcache_normal3f = NULL;
3876 ent->animcache_normal3f_vertexbuffer = NULL;
3877 ent->animcache_normal3f_bufferoffset = 0;
3878 ent->animcache_svector3f = NULL;
3879 ent->animcache_svector3f_vertexbuffer = NULL;
3880 ent->animcache_svector3f_bufferoffset = 0;
3881 ent->animcache_tvector3f = NULL;
3882 ent->animcache_tvector3f_vertexbuffer = NULL;
3883 ent->animcache_tvector3f_bufferoffset = 0;
3884 ent->animcache_vertexmesh = NULL;
3885 ent->animcache_vertexmesh_vertexbuffer = NULL;
3886 ent->animcache_vertexmesh_bufferoffset = 0;
3887 ent->animcache_skeletaltransform3x4 = NULL;
3888 ent->animcache_skeletaltransform3x4buffer = NULL;
3889 ent->animcache_skeletaltransform3x4offset = 0;
3890 ent->animcache_skeletaltransform3x4size = 0;
3894 static void R_AnimCache_UpdateEntityMeshBuffers(entity_render_t *ent, int numvertices)
3898 // check if we need the meshbuffers
3899 if (!vid.useinterleavedarrays)
3902 if (!ent->animcache_vertexmesh && ent->animcache_normal3f)
3903 ent->animcache_vertexmesh = (r_vertexmesh_t *)R_FrameData_Alloc(sizeof(r_vertexmesh_t)*numvertices);
3904 // TODO: upload vertexbuffer?
3905 if (ent->animcache_vertexmesh)
3907 r_refdef.stats[r_stat_animcache_vertexmesh_count] += 1;
3908 r_refdef.stats[r_stat_animcache_vertexmesh_vertices] += numvertices;
3909 r_refdef.stats[r_stat_animcache_vertexmesh_maxvertices] = max(r_refdef.stats[r_stat_animcache_vertexmesh_maxvertices], numvertices);
3910 memcpy(ent->animcache_vertexmesh, ent->model->surfmesh.data_vertexmesh, sizeof(r_vertexmesh_t)*numvertices);
3911 for (i = 0;i < numvertices;i++)
3912 memcpy(ent->animcache_vertexmesh[i].vertex3f, ent->animcache_vertex3f + 3*i, sizeof(float[3]));
3913 if (ent->animcache_svector3f)
3914 for (i = 0;i < numvertices;i++)
3915 memcpy(ent->animcache_vertexmesh[i].svector3f, ent->animcache_svector3f + 3*i, sizeof(float[3]));
3916 if (ent->animcache_tvector3f)
3917 for (i = 0;i < numvertices;i++)
3918 memcpy(ent->animcache_vertexmesh[i].tvector3f, ent->animcache_tvector3f + 3*i, sizeof(float[3]));
3919 if (ent->animcache_normal3f)
3920 for (i = 0;i < numvertices;i++)
3921 memcpy(ent->animcache_vertexmesh[i].normal3f, ent->animcache_normal3f + 3*i, sizeof(float[3]));
3925 qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
3927 dp_model_t *model = ent->model;
3930 // see if this ent is worth caching
3931 if (!model || !model->Draw || !model->AnimateVertices)
3933 // nothing to cache if it contains no animations and has no skeleton
3934 if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3936 // see if it is already cached for gpuskeletal
3937 if (ent->animcache_skeletaltransform3x4)
3939 // see if it is already cached as a mesh
3940 if (ent->animcache_vertex3f)
3942 // check if we need to add normals or tangents
3943 if (ent->animcache_normal3f)
3944 wantnormals = false;
3945 if (ent->animcache_svector3f)
3946 wanttangents = false;
3947 if (!wantnormals && !wanttangents)
3951 // check which kind of cache we need to generate
3952 if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3954 // cache the skeleton so the vertex shader can use it
3955 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3956 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3957 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3958 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3959 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4);
3960 // note: this can fail if the buffer is at the grow limit
3961 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3962 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3964 else if (ent->animcache_vertex3f)
3966 // mesh was already cached but we may need to add normals/tangents
3967 // (this only happens with multiple views, reflections, cameras, etc)
3968 if (wantnormals || wanttangents)
3970 numvertices = model->surfmesh.num_vertices;
3972 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3975 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3976 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3978 model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3979 R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices);
3980 r_refdef.stats[r_stat_animcache_shade_count] += 1;
3981 r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3982 r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3987 // generate mesh cache
3988 numvertices = model->surfmesh.num_vertices;
3989 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3991 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3994 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3995 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3997 model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
3998 R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices);
3999 if (wantnormals || wanttangents)
4001 r_refdef.stats[r_stat_animcache_shade_count] += 1;
4002 r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
4003 r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
4005 r_refdef.stats[r_stat_animcache_shape_count] += 1;
4006 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
4007 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
4012 void R_AnimCache_CacheVisibleEntities(void)
4016 // TODO: thread this
4017 // NOTE: R_PrepareRTLights() also caches entities
4019 for (i = 0;i < r_refdef.scene.numentities;i++)
4020 if (r_refdef.viewcache.entityvisible[i])
4021 R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
4024 //==================================================================================
4026 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)
4029 vec3_t eyemins, eyemaxs;
4030 vec3_t boxmins, boxmaxs;
4031 vec3_t padmins, padmaxs;
4034 dp_model_t *model = r_refdef.scene.worldmodel;
4035 static vec3_t positions[] = {
4036 { 0.5f, 0.5f, 0.5f },
4037 { 0.0f, 0.0f, 0.0f },
4038 { 0.0f, 0.0f, 1.0f },
4039 { 0.0f, 1.0f, 0.0f },
4040 { 0.0f, 1.0f, 1.0f },
4041 { 1.0f, 0.0f, 0.0f },
4042 { 1.0f, 0.0f, 1.0f },
4043 { 1.0f, 1.0f, 0.0f },
4044 { 1.0f, 1.0f, 1.0f },
4047 // sample count can be set to -1 to skip this logic, for flicker-prone objects
4051 // view origin is not used for culling in portal/reflection/refraction renders or isometric views
4052 if (!r_refdef.view.usevieworiginculling)
4055 if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
4058 // expand the eye box a little
4059 eyemins[0] = eye[0] - eyejitter;
4060 eyemaxs[0] = eye[0] + eyejitter;
4061 eyemins[1] = eye[1] - eyejitter;
4062 eyemaxs[1] = eye[1] + eyejitter;
4063 eyemins[2] = eye[2] - eyejitter;
4064 eyemaxs[2] = eye[2] + eyejitter;
4065 // expand the box a little
4066 boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
4067 boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
4068 boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
4069 boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
4070 boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
4071 boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
4072 // make an even larger box for the acceptable area
4073 padmins[0] = boxmins[0] - pad;
4074 padmaxs[0] = boxmaxs[0] + pad;
4075 padmins[1] = boxmins[1] - pad;
4076 padmaxs[1] = boxmaxs[1] + pad;
4077 padmins[2] = boxmins[2] - pad;
4078 padmaxs[2] = boxmaxs[2] + pad;
4080 // return true if eye overlaps enlarged box
4081 if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
4084 // try specific positions in the box first - note that these can be cached
4085 if (r_cullentities_trace_entityocclusion.integer)
4087 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
4089 VectorCopy(eye, start);
4090 end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
4091 end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
4092 end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
4093 //trace_t trace = CL_TraceLine(start, end, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, 0.0f, true, false, NULL, true, true);
4094 trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
4095 // not picky - if the trace ended anywhere in the box we're good
4096 if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4100 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4103 // try various random positions
4104 for (i = 0; i < numsamples; i++)
4106 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
4107 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
4108 if (r_cullentities_trace_entityocclusion.integer)
4110 trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
4111 // not picky - if the trace ended anywhere in the box we're good
4112 if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4115 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4123 static void R_View_UpdateEntityVisible (void)
4128 entity_render_t *ent;
4130 if (r_refdef.envmap || r_fb.water.hideplayer)
4131 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
4132 else if (chase_active.integer || r_fb.water.renderingscene)
4133 renderimask = RENDER_VIEWMODEL;
4135 renderimask = RENDER_EXTERIORMODEL;
4136 if (!r_drawviewmodel.integer)
4137 renderimask |= RENDER_VIEWMODEL;
4138 if (!r_drawexteriormodel.integer)
4139 renderimask |= RENDER_EXTERIORMODEL;
4140 memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4141 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4143 // worldmodel can check visibility
4144 for (i = 0;i < r_refdef.scene.numentities;i++)
4146 ent = r_refdef.scene.entities[i];
4147 if (!(ent->flags & renderimask))
4148 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)))
4149 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))
4150 r_refdef.viewcache.entityvisible[i] = true;
4155 // no worldmodel or it can't check visibility
4156 for (i = 0;i < r_refdef.scene.numentities;i++)
4158 ent = r_refdef.scene.entities[i];
4159 if (!(ent->flags & renderimask))
4160 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)))
4161 r_refdef.viewcache.entityvisible[i] = true;
4164 if (r_cullentities_trace.integer)
4166 for (i = 0;i < r_refdef.scene.numentities;i++)
4168 if (!r_refdef.viewcache.entityvisible[i])
4170 ent = r_refdef.scene.entities[i];
4171 if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4173 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4174 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))
4175 ent->last_trace_visibility = realtime;
4176 if (ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
4177 r_refdef.viewcache.entityvisible[i] = 0;
4183 /// only used if skyrendermasked, and normally returns false
4184 static int R_DrawBrushModelsSky (void)
4187 entity_render_t *ent;
4190 for (i = 0;i < r_refdef.scene.numentities;i++)
4192 if (!r_refdef.viewcache.entityvisible[i])
4194 ent = r_refdef.scene.entities[i];
4195 if (!ent->model || !ent->model->DrawSky)
4197 ent->model->DrawSky(ent);
4203 static void R_DrawNoModel(entity_render_t *ent);
4204 static void R_DrawModels(void)
4207 entity_render_t *ent;
4209 for (i = 0;i < r_refdef.scene.numentities;i++)
4211 if (!r_refdef.viewcache.entityvisible[i])
4213 ent = r_refdef.scene.entities[i];
4214 r_refdef.stats[r_stat_entities]++;
4216 if (ent->model && !strncmp(ent->model->name, "models/proto_", 13))
4219 Matrix4x4_ToVectors(&ent->matrix, f, l, u, o);
4220 Con_Printf("R_DrawModels\n");
4221 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]);
4222 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);
4223 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);
4226 if (ent->model && ent->model->Draw != NULL)
4227 ent->model->Draw(ent);
4233 static void R_DrawModelsDepth(void)
4236 entity_render_t *ent;
4238 for (i = 0;i < r_refdef.scene.numentities;i++)
4240 if (!r_refdef.viewcache.entityvisible[i])
4242 ent = r_refdef.scene.entities[i];
4243 if (ent->model && ent->model->DrawDepth != NULL)
4244 ent->model->DrawDepth(ent);
4248 static void R_DrawModelsDebug(void)
4251 entity_render_t *ent;
4253 for (i = 0;i < r_refdef.scene.numentities;i++)
4255 if (!r_refdef.viewcache.entityvisible[i])
4257 ent = r_refdef.scene.entities[i];
4258 if (ent->model && ent->model->DrawDebug != NULL)
4259 ent->model->DrawDebug(ent);
4263 static void R_DrawModelsAddWaterPlanes(void)
4266 entity_render_t *ent;
4268 for (i = 0;i < r_refdef.scene.numentities;i++)
4270 if (!r_refdef.viewcache.entityvisible[i])
4272 ent = r_refdef.scene.entities[i];
4273 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4274 ent->model->DrawAddWaterPlanes(ent);
4278 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}};
4280 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4282 if (r_hdr_irisadaptation.integer)
4287 vec3_t diffusenormal;
4289 vec_t brightness = 0.0f;
4294 VectorCopy(r_refdef.view.forward, forward);
4295 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4297 p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4298 p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4299 p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4300 R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4301 d = DotProduct(forward, diffusenormal);
4302 brightness += VectorLength(ambient);
4304 brightness += d * VectorLength(diffuse);
4306 brightness *= 1.0f / c;
4307 brightness += 0.00001f; // make sure it's never zero
4308 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4309 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4310 current = r_hdr_irisadaptation_value.value;
4312 current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4313 else if (current > goal)
4314 current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4315 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4316 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4318 else if (r_hdr_irisadaptation_value.value != 1.0f)
4319 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4322 static void R_View_SetFrustum(const int *scissor)
4325 double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4326 vec3_t forward, left, up, origin, v;
4330 // flipped x coordinates (because x points left here)
4331 fpx = 1.0 - 2.0 * (scissor[0] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4332 fnx = 1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4333 // non-flipped y coordinates
4334 fny = -1.0 + 2.0 * (scissor[1] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4335 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4338 // we can't trust r_refdef.view.forward and friends in reflected scenes
4339 Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4342 r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4343 r_refdef.view.frustum[0].normal[1] = 0 - 0;
4344 r_refdef.view.frustum[0].normal[2] = -1 - 0;
4345 r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4346 r_refdef.view.frustum[1].normal[1] = 0 + 0;
4347 r_refdef.view.frustum[1].normal[2] = -1 + 0;
4348 r_refdef.view.frustum[2].normal[0] = 0 - 0;
4349 r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4350 r_refdef.view.frustum[2].normal[2] = -1 - 0;
4351 r_refdef.view.frustum[3].normal[0] = 0 + 0;
4352 r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4353 r_refdef.view.frustum[3].normal[2] = -1 + 0;
4357 zNear = r_refdef.nearclip;
4358 nudge = 1.0 - 1.0 / (1<<23);
4359 r_refdef.view.frustum[4].normal[0] = 0 - 0;
4360 r_refdef.view.frustum[4].normal[1] = 0 - 0;
4361 r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4362 r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4363 r_refdef.view.frustum[5].normal[0] = 0 + 0;
4364 r_refdef.view.frustum[5].normal[1] = 0 + 0;
4365 r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4366 r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4372 r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4373 r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4374 r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4375 r_refdef.view.frustum[0].dist = m[15] - m[12];
4377 r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4378 r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4379 r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4380 r_refdef.view.frustum[1].dist = m[15] + m[12];
4382 r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4383 r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4384 r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4385 r_refdef.view.frustum[2].dist = m[15] - m[13];
4387 r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4388 r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4389 r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4390 r_refdef.view.frustum[3].dist = m[15] + m[13];
4392 r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4393 r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4394 r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4395 r_refdef.view.frustum[4].dist = m[15] - m[14];
4397 r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4398 r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4399 r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4400 r_refdef.view.frustum[5].dist = m[15] + m[14];
4403 if (r_refdef.view.useperspective)
4405 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4406 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]);
4407 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]);
4408 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]);
4409 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]);
4411 // then the normals from the corners relative to origin
4412 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4413 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4414 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4415 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4417 // in a NORMAL view, forward cross left == up
4418 // in a REFLECTED view, forward cross left == down
4419 // so our cross products above need to be adjusted for a left handed coordinate system
4420 CrossProduct(forward, left, v);
4421 if(DotProduct(v, up) < 0)
4423 VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4424 VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4425 VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4426 VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4429 // Leaving those out was a mistake, those were in the old code, and they
4430 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4431 // I couldn't reproduce it after adding those normalizations. --blub
4432 VectorNormalize(r_refdef.view.frustum[0].normal);
4433 VectorNormalize(r_refdef.view.frustum[1].normal);
4434 VectorNormalize(r_refdef.view.frustum[2].normal);
4435 VectorNormalize(r_refdef.view.frustum[3].normal);
4437 // make the corners absolute
4438 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4439 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4440 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4441 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4444 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4446 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4447 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4448 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4449 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4450 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4454 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4455 VectorScale(left, 1.0f, r_refdef.view.frustum[1].normal);
4456 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4457 VectorScale(up, 1.0f, r_refdef.view.frustum[3].normal);
4458 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4459 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4460 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4461 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4462 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4463 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4465 r_refdef.view.numfrustumplanes = 5;
4467 if (r_refdef.view.useclipplane)
4469 r_refdef.view.numfrustumplanes = 6;
4470 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4473 for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4474 PlaneClassify(r_refdef.view.frustum + i);
4476 // LordHavoc: note to all quake engine coders, Quake had a special case
4477 // for 90 degrees which assumed a square view (wrong), so I removed it,
4478 // Quake2 has it disabled as well.
4480 // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4481 //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4482 //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4483 //PlaneClassify(&frustum[0]);
4485 // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4486 //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4487 //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4488 //PlaneClassify(&frustum[1]);
4490 // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4491 //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4492 //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4493 //PlaneClassify(&frustum[2]);
4495 // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4496 //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4497 //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4498 //PlaneClassify(&frustum[3]);
4501 //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4502 //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4503 //PlaneClassify(&frustum[4]);
4506 static void R_View_UpdateWithScissor(const int *myscissor)
4508 R_Main_ResizeViewCache();
4509 R_View_SetFrustum(myscissor);
4510 R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4511 R_View_UpdateEntityVisible();
4514 static void R_View_Update(void)
4516 R_Main_ResizeViewCache();
4517 R_View_SetFrustum(NULL);
4518 R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4519 R_View_UpdateEntityVisible();
4522 float viewscalefpsadjusted = 1.0f;
4524 static void R_GetScaledViewSize(int width, int height, int *outwidth, int *outheight)
4526 float scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
4527 scale = bound(0.03125f, scale, 1.0f);
4528 *outwidth = (int)ceil(width * scale);
4529 *outheight = (int)ceil(height * scale);
4532 void R_SetupView(qboolean allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4534 const float *customclipplane = NULL;
4536 int /*rtwidth,*/ rtheight;
4537 if (r_refdef.view.useclipplane && allowwaterclippingplane)
4539 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4540 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4541 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4542 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4543 dist = r_refdef.view.clipplane.dist;
4544 plane[0] = r_refdef.view.clipplane.normal[0];
4545 plane[1] = r_refdef.view.clipplane.normal[1];
4546 plane[2] = r_refdef.view.clipplane.normal[2];
4548 customclipplane = plane;
4551 //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
4552 rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
4554 if (!r_refdef.view.useperspective)
4555 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);
4556 else if (vid.stencil && r_useinfinitefarclip.integer)
4557 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);
4559 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);
4560 R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4561 R_SetViewport(&r_refdef.view.viewport);
4564 void R_EntityMatrix(const matrix4x4_t *matrix)
4566 if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4568 gl_modelmatrixchanged = false;
4569 gl_modelmatrix = *matrix;
4570 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4571 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4572 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4573 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4575 switch(vid.renderpath)
4577 case RENDERPATH_GL20:
4578 case RENDERPATH_GLES2:
4579 if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4580 if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4586 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4588 r_viewport_t viewport;
4592 // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
4593 R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4594 R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4595 R_SetViewport(&viewport);
4596 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4597 GL_Color(1, 1, 1, 1);
4598 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4599 GL_BlendFunc(GL_ONE, GL_ZERO);
4600 GL_ScissorTest(false);
4601 GL_DepthMask(false);
4602 GL_DepthRange(0, 1);
4603 GL_DepthTest(false);
4604 GL_DepthFunc(GL_LEQUAL);
4605 R_EntityMatrix(&identitymatrix);
4606 R_Mesh_ResetTextureState();
4607 GL_PolygonOffset(0, 0);
4608 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
4609 switch(vid.renderpath)
4611 case RENDERPATH_GL20:
4612 case RENDERPATH_GLES2:
4613 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4616 GL_CullFace(GL_NONE);
4621 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4623 R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4626 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4628 R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4629 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4630 GL_Color(1, 1, 1, 1);
4631 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4632 GL_BlendFunc(GL_ONE, GL_ZERO);
4633 GL_ScissorTest(true);
4635 GL_DepthRange(0, 1);
4637 GL_DepthFunc(GL_LEQUAL);
4638 R_EntityMatrix(&identitymatrix);
4639 R_Mesh_ResetTextureState();
4640 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4641 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
4642 switch(vid.renderpath)
4644 case RENDERPATH_GL20:
4645 case RENDERPATH_GLES2:
4646 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4649 GL_CullFace(r_refdef.view.cullface_back);
4654 R_RenderView_UpdateViewVectors
4657 void R_RenderView_UpdateViewVectors(void)
4659 // break apart the view matrix into vectors for various purposes
4660 // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4661 // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4662 Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4663 VectorNegate(r_refdef.view.left, r_refdef.view.right);
4664 // make an inverted copy of the view matrix for tracking sprites
4665 Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4668 void R_RenderTarget_FreeUnused(qboolean force)
4671 end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
4672 for (i = 0; i < end; i++)
4674 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4675 // free resources for rendertargets that have not been used for a while
4676 // (note: this check is run after the frame render, so any targets used
4677 // this frame will not be affected even at low framerates)
4678 if (r && (realtime - r->lastusetime > 0.2 || force))
4681 R_Mesh_DestroyFramebufferObject(r->fbo);
4682 for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4683 if (r->colortexture[j])
4684 R_FreeTexture(r->colortexture[j]);
4685 if (r->depthtexture)
4686 R_FreeTexture(r->depthtexture);
4687 Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4692 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4694 float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4698 y2 = (th - y - h) * ih;
4709 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)
4712 r_rendertarget_t *r = NULL;
4714 // first try to reuse an existing slot if possible
4715 end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
4716 for (i = 0; i < end; i++)
4718 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4719 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)
4724 // no unused exact match found, so we have to make one in the first unused slot
4725 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4726 r->texturewidth = texturewidth;
4727 r->textureheight = textureheight;
4728 r->colortextype[0] = colortextype0;
4729 r->colortextype[1] = colortextype1;
4730 r->colortextype[2] = colortextype2;
4731 r->colortextype[3] = colortextype3;
4732 r->depthtextype = depthtextype;
4733 r->depthisrenderbuffer = depthisrenderbuffer;
4734 for (j = 0; j < 4; j++)
4735 if (r->colortextype[j])
4736 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);
4737 if (r->depthtextype)
4739 if (r->depthisrenderbuffer)
4740 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);
4742 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);
4744 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4746 r_refdef.stats[r_stat_rendertargets_used]++;
4747 r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4748 r->lastusetime = realtime;
4749 R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4753 static void R_Water_StartFrame(void)
4755 int waterwidth, waterheight;
4757 if (vid.width > (int)vid.maxtexturesize_2d || vid.height > (int)vid.maxtexturesize_2d)
4760 // set waterwidth and waterheight to the water resolution that will be
4761 // used (often less than the screen resolution for faster rendering)
4762 waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width);
4763 waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height);
4764 R_GetScaledViewSize(waterwidth, waterheight, &waterwidth, &waterheight);
4766 if (!r_water.integer || r_showsurfaces.integer)
4767 waterwidth = waterheight = 0;
4769 // set up variables that will be used in shader setup
4770 r_fb.water.waterwidth = waterwidth;
4771 r_fb.water.waterheight = waterheight;
4772 r_fb.water.texturewidth = waterwidth;
4773 r_fb.water.textureheight = waterheight;
4774 r_fb.water.camerawidth = waterwidth;
4775 r_fb.water.cameraheight = waterheight;
4776 r_fb.water.screenscale[0] = 0.5f;
4777 r_fb.water.screenscale[1] = 0.5f;
4778 r_fb.water.screencenter[0] = 0.5f;
4779 r_fb.water.screencenter[1] = 0.5f;
4780 r_fb.water.enabled = waterwidth != 0;
4782 r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4783 r_fb.water.numwaterplanes = 0;
4786 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4788 int planeindex, bestplaneindex, vertexindex;
4789 vec3_t mins, maxs, normal, center, v, n;
4790 vec_t planescore, bestplanescore;
4792 r_waterstate_waterplane_t *p;
4793 texture_t *t = R_GetCurrentTexture(surface->texture);
4795 rsurface.texture = t;
4796 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4797 // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4798 if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4800 // average the vertex normals, find the surface bounds (after deformvertexes)
4801 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4802 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4803 VectorCopy(n, normal);
4804 VectorCopy(v, mins);
4805 VectorCopy(v, maxs);
4806 for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4808 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4809 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4810 VectorAdd(normal, n, normal);
4811 mins[0] = min(mins[0], v[0]);
4812 mins[1] = min(mins[1], v[1]);
4813 mins[2] = min(mins[2], v[2]);
4814 maxs[0] = max(maxs[0], v[0]);
4815 maxs[1] = max(maxs[1], v[1]);
4816 maxs[2] = max(maxs[2], v[2]);
4818 VectorNormalize(normal);
4819 VectorMAM(0.5f, mins, 0.5f, maxs, center);
4821 VectorCopy(normal, plane.normal);
4822 VectorNormalize(plane.normal);
4823 plane.dist = DotProduct(center, plane.normal);
4824 PlaneClassify(&plane);
4825 if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4827 // skip backfaces (except if nocullface is set)
4828 // if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4830 VectorNegate(plane.normal, plane.normal);
4832 PlaneClassify(&plane);
4836 // find a matching plane if there is one
4837 bestplaneindex = -1;
4838 bestplanescore = 1048576.0f;
4839 for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4841 if(p->camera_entity == t->camera_entity)
4843 planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4844 if (bestplaneindex < 0 || bestplanescore > planescore)
4846 bestplaneindex = planeindex;
4847 bestplanescore = planescore;
4851 planeindex = bestplaneindex;
4853 // if this surface does not fit any known plane rendered this frame, add one
4854 if (planeindex < 0 || bestplanescore > 0.001f)
4856 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4858 // store the new plane
4859 planeindex = r_fb.water.numwaterplanes++;
4860 p = r_fb.water.waterplanes + planeindex;
4862 // clear materialflags and pvs
4863 p->materialflags = 0;
4864 p->pvsvalid = false;
4865 p->camera_entity = t->camera_entity;
4866 VectorCopy(mins, p->mins);
4867 VectorCopy(maxs, p->maxs);
4871 // We're totally screwed.
4877 // merge mins/maxs when we're adding this surface to the plane
4878 p = r_fb.water.waterplanes + planeindex;
4879 p->mins[0] = min(p->mins[0], mins[0]);
4880 p->mins[1] = min(p->mins[1], mins[1]);
4881 p->mins[2] = min(p->mins[2], mins[2]);
4882 p->maxs[0] = max(p->maxs[0], maxs[0]);
4883 p->maxs[1] = max(p->maxs[1], maxs[1]);
4884 p->maxs[2] = max(p->maxs[2], maxs[2]);
4886 // merge this surface's materialflags into the waterplane
4887 p->materialflags |= t->currentmaterialflags;
4888 if(!(p->materialflags & MATERIALFLAG_CAMERA))
4890 // merge this surface's PVS into the waterplane
4891 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4892 && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4894 r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4900 extern cvar_t r_drawparticles;
4901 extern cvar_t r_drawdecals;
4903 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4906 r_refdef_view_t originalview;
4907 r_refdef_view_t myview;
4908 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;
4909 r_waterstate_waterplane_t *p;
4911 r_rendertarget_t *rt;
4913 originalview = r_refdef.view;
4915 // lowquality hack, temporarily shut down some cvars and restore afterwards
4916 qualityreduction = r_water_lowquality.integer;
4917 if (qualityreduction > 0)
4919 if (qualityreduction >= 1)
4921 old_r_shadows = r_shadows.integer;
4922 old_r_worldrtlight = r_shadow_realtime_world.integer;
4923 old_r_dlight = r_shadow_realtime_dlight.integer;
4924 Cvar_SetValueQuick(&r_shadows, 0);
4925 Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4926 Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4928 if (qualityreduction >= 2)
4930 old_r_dynamic = r_dynamic.integer;
4931 old_r_particles = r_drawparticles.integer;
4932 old_r_decals = r_drawdecals.integer;
4933 Cvar_SetValueQuick(&r_dynamic, 0);
4934 Cvar_SetValueQuick(&r_drawparticles, 0);
4935 Cvar_SetValueQuick(&r_drawdecals, 0);
4939 for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4941 p->rt_reflection = NULL;
4942 p->rt_refraction = NULL;
4943 p->rt_camera = NULL;
4947 r_refdef.view = originalview;
4948 r_refdef.view.showdebug = false;
4949 r_refdef.view.width = r_fb.water.waterwidth;
4950 r_refdef.view.height = r_fb.water.waterheight;
4951 r_refdef.view.useclipplane = true;
4952 myview = r_refdef.view;
4953 r_fb.water.renderingscene = true;
4954 for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4956 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4959 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4961 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);
4962 if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4964 r_refdef.view = myview;
4965 Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4966 Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4967 if(r_water_scissormode.integer)
4969 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4970 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4972 p->rt_reflection = NULL;
4973 p->rt_refraction = NULL;
4974 p->rt_camera = NULL;
4979 r_refdef.view.clipplane = p->plane;
4980 // reflected view origin may be in solid, so don't cull with it
4981 r_refdef.view.usevieworiginculling = false;
4982 // reverse the cullface settings for this render
4983 r_refdef.view.cullface_front = GL_FRONT;
4984 r_refdef.view.cullface_back = GL_BACK;
4985 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4987 r_refdef.view.usecustompvs = true;
4989 memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4991 memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4994 r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4995 R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4996 GL_ScissorTest(false);
4997 R_ClearScreen(r_refdef.fogenabled);
4998 GL_ScissorTest(true);
4999 if(r_water_scissormode.integer & 2)
5000 R_View_UpdateWithScissor(myscissor);
5003 R_AnimCache_CacheVisibleEntities();
5004 if(r_water_scissormode.integer & 1)
5005 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
5006 R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5008 r_fb.water.hideplayer = false;
5009 p->rt_reflection = rt;
5012 // render the normal view scene and copy into texture
5013 // (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)
5014 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
5016 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);
5017 if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5019 r_refdef.view = myview;
5020 if(r_water_scissormode.integer)
5022 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
5023 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
5025 p->rt_reflection = NULL;
5026 p->rt_refraction = NULL;
5027 p->rt_camera = NULL;
5032 r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
5034 r_refdef.view.clipplane = p->plane;
5035 VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5036 r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5038 if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
5040 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5041 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
5042 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5043 R_RenderView_UpdateViewVectors();
5044 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5046 r_refdef.view.usecustompvs = true;
5047 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);
5051 PlaneClassify(&r_refdef.view.clipplane);
5053 R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5054 GL_ScissorTest(false);
5055 R_ClearScreen(r_refdef.fogenabled);
5056 GL_ScissorTest(true);
5057 if(r_water_scissormode.integer & 2)
5058 R_View_UpdateWithScissor(myscissor);
5061 R_AnimCache_CacheVisibleEntities();
5062 if(r_water_scissormode.integer & 1)
5063 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
5064 R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5066 r_fb.water.hideplayer = false;
5067 p->rt_refraction = rt;
5069 else if (p->materialflags & MATERIALFLAG_CAMERA)
5071 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);
5072 if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5074 r_refdef.view = myview;
5076 r_refdef.view.clipplane = p->plane;
5077 VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5078 r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5080 r_refdef.view.width = r_fb.water.camerawidth;
5081 r_refdef.view.height = r_fb.water.cameraheight;
5082 r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
5083 r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
5084 r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
5085 r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
5087 if(p->camera_entity)
5089 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5090 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5093 // note: all of the view is used for displaying... so
5094 // there is no use in scissoring
5096 // reverse the cullface settings for this render
5097 r_refdef.view.cullface_front = GL_FRONT;
5098 r_refdef.view.cullface_back = GL_BACK;
5099 // also reverse the view matrix
5100 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
5101 R_RenderView_UpdateViewVectors();
5102 if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5104 r_refdef.view.usecustompvs = true;
5105 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);
5108 // camera needs no clipplane
5109 r_refdef.view.useclipplane = false;
5110 // TODO: is the camera origin always valid? if so we don't need to clear this
5111 r_refdef.view.usevieworiginculling = false;
5113 PlaneClassify(&r_refdef.view.clipplane);
5115 r_fb.water.hideplayer = false;
5117 R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5118 GL_ScissorTest(false);
5119 R_ClearScreen(r_refdef.fogenabled);
5120 GL_ScissorTest(true);
5122 R_AnimCache_CacheVisibleEntities();
5123 R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5125 r_fb.water.hideplayer = false;
5130 r_fb.water.renderingscene = false;
5131 r_refdef.view = originalview;
5132 R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5134 R_AnimCache_CacheVisibleEntities();
5137 r_refdef.view = originalview;
5138 r_fb.water.renderingscene = false;
5139 Cvar_SetValueQuick(&r_water, 0);
5140 Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed! Turned off r_water.\n");
5142 // lowquality hack, restore cvars
5143 if (qualityreduction > 0)
5145 if (qualityreduction >= 1)
5147 Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5148 Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5149 Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5151 if (qualityreduction >= 2)
5153 Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5154 Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5155 Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5160 static void R_Bloom_StartFrame(void)
5162 int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
5163 int viewwidth, viewheight;
5164 textype_t textype = TEXTYPE_COLORBUFFER;
5166 // clear the pointers to rendertargets from last frame as they're stale
5167 r_fb.rt_screen = NULL;
5168 r_fb.rt_bloom = NULL;
5170 switch (vid.renderpath)
5172 case RENDERPATH_GL20:
5173 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5174 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5175 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5176 // for simplicity, bloom requires FBO render to texture, which basically all video drivers support now
5177 if (!vid.support.ext_framebuffer_object)
5180 case RENDERPATH_GLES2:
5181 r_fb.usedepthtextures = false;
5185 if (r_viewscale_fpsscaling.integer)
5187 double actualframetime;
5188 double targetframetime;
5190 actualframetime = r_refdef.lastdrawscreentime;
5191 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5192 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5193 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5194 if (r_viewscale_fpsscaling_stepsize.value > 0)
5195 adjust = (int)(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5196 viewscalefpsadjusted += adjust;
5197 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5200 viewscalefpsadjusted = 1.0f;
5202 R_GetScaledViewSize(r_refdef.view.width, r_refdef.view.height, &viewwidth, &viewheight);
5204 // set bloomwidth and bloomheight to the bloom resolution that will be
5205 // used (often less than the screen resolution for faster rendering)
5206 r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, vid.width);
5207 r_fb.bloomheight = r_fb.bloomwidth * vid.height / vid.width;
5208 r_fb.bloomheight = bound(1, r_fb.bloomheight, vid.height);
5209 r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5210 r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5212 // calculate desired texture sizes
5213 screentexturewidth = viewwidth;
5214 screentextureheight = viewheight;
5215 bloomtexturewidth = r_fb.bloomwidth;
5216 bloomtextureheight = r_fb.bloomheight;
5218 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))
5220 Cvar_SetValueQuick(&r_bloom, 0);
5221 Cvar_SetValueQuick(&r_motionblur, 0);
5222 Cvar_SetValueQuick(&r_damageblur, 0);
5225 // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5226 if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5228 if (r_fb.ghosttexture)
5229 R_FreeTexture(r_fb.ghosttexture);
5230 r_fb.ghosttexture = NULL;
5232 r_fb.screentexturewidth = screentexturewidth;
5233 r_fb.screentextureheight = screentextureheight;
5234 r_fb.textype = textype;
5236 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5238 if (r_motionblur.value > 0 || r_damageblur.value > 0)
5239 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);
5240 r_fb.ghosttexture_valid = false;
5244 if (r_bloom.integer)
5246 // bloom texture is a different resolution
5247 r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.width);
5248 r_fb.bloomheight = r_fb.bloomwidth * r_refdef.view.height / r_refdef.view.width;
5249 r_fb.bloomheight = bound(1, r_fb.bloomheight, r_refdef.view.height);
5252 r_fb.bloomwidth = r_fb.bloomheight = 0;
5254 r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5256 r_refdef.view.clear = true;
5259 static void R_Bloom_MakeTexture(void)
5262 float xoffset, yoffset, r, brighten;
5263 float colorscale = r_bloom_colorscale.value;
5264 r_viewport_t bloomviewport;
5265 r_rendertarget_t *prev, *cur;
5266 textype_t textype = r_fb.rt_screen->colortextype[0];
5268 r_refdef.stats[r_stat_bloom]++;
5270 R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5272 // scale down screen texture to the bloom texture size
5274 prev = r_fb.rt_screen;
5275 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5276 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5277 R_SetViewport(&bloomviewport);
5278 GL_CullFace(GL_NONE);
5279 GL_DepthTest(false);
5280 GL_BlendFunc(GL_ONE, GL_ZERO);
5281 GL_Color(colorscale, colorscale, colorscale, 1);
5282 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5283 // TODO: do boxfilter scale-down in shader?
5284 R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, true);
5285 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5286 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5287 // we now have a properly scaled bloom image
5289 // multiply bloom image by itself as many times as desired to darken it
5290 // TODO: if people actually use this it could be done more quickly in the previous shader pass
5291 for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5294 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5295 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5297 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5299 GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128);
5300 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5301 GL_Color(1,1,1,1); // no fix factor supported here
5302 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5303 R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, false);
5304 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5305 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5308 range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5309 brighten = r_bloom_brighten.value;
5310 brighten = sqrt(brighten);
5312 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5314 for (dir = 0;dir < 2;dir++)
5317 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5318 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5319 // blend on at multiple vertical offsets to achieve a vertical blur
5320 // TODO: do offset blends using GLSL
5321 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5322 GL_BlendFunc(GL_ONE, GL_ZERO);
5323 R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, false);
5324 for (x = -range;x <= range;x++)
5326 if (!dir){xoffset = 0;yoffset = x;}
5327 else {xoffset = x;yoffset = 0;}
5328 xoffset /= (float)prev->texturewidth;
5329 yoffset /= (float)prev->textureheight;
5330 // compute a texcoord array with the specified x and y offset
5331 r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5332 r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5333 r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5334 r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5335 r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5336 r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5337 r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5338 r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5339 // this r value looks like a 'dot' particle, fading sharply to
5340 // black at the edges
5341 // (probably not realistic but looks good enough)
5342 //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5343 //r = brighten/(range*2+1);
5344 r = brighten / (range * 2 + 1);
5346 r *= (1 - x*x/(float)((range+1)*(range+1)));
5349 GL_Color(r, r, r, 1);
5350 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5351 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5352 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5353 GL_BlendFunc(GL_ONE, GL_ONE);
5357 // now we have the bloom image, so keep track of it
5358 r_fb.rt_bloom = cur;
5361 static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5363 dpuint64 permutation;
5364 float uservecs[4][4];
5365 rtexture_t *viewtexture;
5366 rtexture_t *bloomtexture;
5368 R_EntityMatrix(&identitymatrix);
5370 if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
5372 // declare variables
5373 float blur_factor, blur_mouseaccel, blur_velocity;
5374 static float blur_average;
5375 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5377 // set a goal for the factoring
5378 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value)
5379 / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5380 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value)
5381 / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5382 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value)
5383 + (blur_mouseaccel * r_motionblur_mousefactor.value));
5385 // from the goal, pick an averaged value between goal and last value
5386 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5387 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5389 // enforce minimum amount of blur
5390 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5392 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5394 // calculate values into a standard alpha
5395 cl.motionbluralpha = 1 - exp(-
5397 (r_motionblur.value * blur_factor / 80)
5399 (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5402 max(0.0001, cl.time - cl.oldtime) // fps independent
5405 // randomization for the blur value to combat persistent ghosting
5406 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5407 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5410 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5411 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5413 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5414 GL_Color(1, 1, 1, cl.motionbluralpha);
5415 R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5416 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5417 R_SetupShader_Generic(r_fb.ghosttexture, NULL, GL_MODULATE, 1, false, true, true);
5418 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5419 r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5422 // updates old view angles for next pass
5423 VectorCopy(cl.viewangles, blur_oldangles);
5425 // copy view into the ghost texture
5426 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5427 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5428 r_fb.ghosttexture_valid = true;
5431 if (r_fb.bloomwidth)
5433 // make the bloom texture
5434 R_Bloom_MakeTexture();
5437 #if _MSC_VER >= 1400
5438 #define sscanf sscanf_s
5440 memset(uservecs, 0, sizeof(uservecs));
5441 if (r_glsl_postprocess_uservec1_enable.integer)
5442 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5443 if (r_glsl_postprocess_uservec2_enable.integer)
5444 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5445 if (r_glsl_postprocess_uservec3_enable.integer)
5446 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5447 if (r_glsl_postprocess_uservec4_enable.integer)
5448 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5450 // render to the screen fbo
5451 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5452 GL_Color(1, 1, 1, 1);
5453 GL_BlendFunc(GL_ONE, GL_ZERO);
5455 viewtexture = r_fb.rt_screen->colortexture[0];
5456 bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5458 if (r_rendertarget_debug.integer >= 0)
5460 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5461 if (rt && rt->colortexture[0])
5463 viewtexture = rt->colortexture[0];
5464 bloomtexture = NULL;
5468 R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5469 switch(vid.renderpath)
5471 case RENDERPATH_GL20:
5472 case RENDERPATH_GLES2:
5474 (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5475 | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5476 | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5477 | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5478 | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5479 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5480 if (r_glsl_permutation->tex_Texture_First >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , viewtexture);
5481 if (r_glsl_permutation->tex_Texture_Second >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second , bloomtexture);
5482 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps );
5483 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]);
5484 if (r_glsl_permutation->loc_PixelSize >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5485 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]);
5486 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]);
5487 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]);
5488 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]);
5489 if (r_glsl_permutation->loc_Saturation >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation , r_glsl_saturation.value);
5490 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
5491 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);
5494 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5495 r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5498 matrix4x4_t r_waterscrollmatrix;
5500 void R_UpdateFog(void)
5503 if (gamemode == GAME_NEHAHRA)
5505 if (gl_fogenable.integer)
5507 r_refdef.oldgl_fogenable = true;
5508 r_refdef.fog_density = gl_fogdensity.value;
5509 r_refdef.fog_red = gl_fogred.value;
5510 r_refdef.fog_green = gl_foggreen.value;
5511 r_refdef.fog_blue = gl_fogblue.value;
5512 r_refdef.fog_alpha = 1;
5513 r_refdef.fog_start = 0;
5514 r_refdef.fog_end = gl_skyclip.value;
5515 r_refdef.fog_height = 1<<30;
5516 r_refdef.fog_fadedepth = 128;
5518 else if (r_refdef.oldgl_fogenable)
5520 r_refdef.oldgl_fogenable = false;
5521 r_refdef.fog_density = 0;
5522 r_refdef.fog_red = 0;
5523 r_refdef.fog_green = 0;
5524 r_refdef.fog_blue = 0;
5525 r_refdef.fog_alpha = 0;
5526 r_refdef.fog_start = 0;
5527 r_refdef.fog_end = 0;
5528 r_refdef.fog_height = 1<<30;
5529 r_refdef.fog_fadedepth = 128;
5534 r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5535 r_refdef.fog_start = max(0, r_refdef.fog_start);
5536 r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5538 if (r_refdef.fog_density && r_drawfog.integer)
5540 r_refdef.fogenabled = true;
5541 // this is the point where the fog reaches 0.9986 alpha, which we
5542 // consider a good enough cutoff point for the texture
5543 // (0.9986 * 256 == 255.6)
5544 if (r_fog_exp2.integer)
5545 r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5547 r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5548 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5549 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5550 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5551 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5552 R_BuildFogHeightTexture();
5553 // fog color was already set
5554 // update the fog texture
5555 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)
5556 R_BuildFogTexture();
5557 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5558 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5561 r_refdef.fogenabled = false;
5564 if (r_refdef.fog_density)
5566 r_refdef.fogcolor[0] = r_refdef.fog_red;
5567 r_refdef.fogcolor[1] = r_refdef.fog_green;
5568 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5570 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5571 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5572 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5573 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5577 VectorCopy(r_refdef.fogcolor, fogvec);
5578 // color.rgb *= ContrastBoost * SceneBrightness;
5579 VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5580 r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5581 r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5582 r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5587 void R_UpdateVariables(void)
5591 r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5593 r_refdef.farclip = r_farclip_base.value;
5594 if (r_refdef.scene.worldmodel)
5595 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5596 r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5598 if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5599 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5600 r_refdef.polygonfactor = 0;
5601 r_refdef.polygonoffset = 0;
5602 r_refdef.shadowpolygonfactor = r_refdef.polygonfactor + r_shadow_polygonfactor.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
5603 r_refdef.shadowpolygonoffset = r_refdef.polygonoffset + r_shadow_polygonoffset.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
5605 r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5606 r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5607 r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5608 r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5609 r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5610 if (FAKELIGHT_ENABLED)
5612 r_refdef.scene.lightmapintensity *= r_fakelight_intensity.value;
5614 else if (r_refdef.scene.worldmodel)
5616 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5618 if (r_showsurfaces.integer)
5620 r_refdef.scene.rtworld = false;
5621 r_refdef.scene.rtworldshadows = false;
5622 r_refdef.scene.rtdlight = false;
5623 r_refdef.scene.rtdlightshadows = false;
5624 r_refdef.scene.lightmapintensity = 0;
5627 r_gpuskeletal = false;
5628 switch(vid.renderpath)
5630 case RENDERPATH_GL20:
5631 r_gpuskeletal = vid.support.arb_uniform_buffer_object && r_glsl_skeletal.integer && !r_showsurfaces.integer; // FIXME add r_showsurfaces support to GLSL skeletal!
5632 case RENDERPATH_GLES2:
5633 if(!vid_gammatables_trivial)
5635 if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5637 // build GLSL gamma texture
5638 #define RAMPWIDTH 256
5639 unsigned short ramp[RAMPWIDTH * 3];
5640 unsigned char rampbgr[RAMPWIDTH][4];
5643 r_texture_gammaramps_serial = vid_gammatables_serial;
5645 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5646 for(i = 0; i < RAMPWIDTH; ++i)
5648 rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5649 rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5650 rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5653 if (r_texture_gammaramps)
5655 R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1);
5659 r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5665 // remove GLSL gamma texture
5671 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5672 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5678 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5679 if( scenetype != r_currentscenetype ) {
5680 // store the old scenetype
5681 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5682 r_currentscenetype = scenetype;
5683 // move in the new scene
5684 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5693 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5695 // of course, we could also add a qboolean that provides a lock state and a ReleaseScenePointer function..
5696 if( scenetype == r_currentscenetype ) {
5697 return &r_refdef.scene;
5699 return &r_scenes_store[ scenetype ];
5703 static int R_SortEntities_Compare(const void *ap, const void *bp)
5705 const entity_render_t *a = *(const entity_render_t **)ap;
5706 const entity_render_t *b = *(const entity_render_t **)bp;
5709 if(a->model < b->model)
5711 if(a->model > b->model)
5715 // TODO possibly calculate the REAL skinnum here first using
5717 if(a->skinnum < b->skinnum)
5719 if(a->skinnum > b->skinnum)
5722 // everything we compared is equal
5725 static void R_SortEntities(void)
5727 // below or equal 2 ents, sorting never gains anything
5728 if(r_refdef.scene.numentities <= 2)
5731 qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5739 extern cvar_t r_shadow_bouncegrid;
5740 extern cvar_t v_isometric;
5741 extern void V_MakeViewIsometric(void);
5742 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5744 matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5746 rtexture_t *viewdepthtexture = NULL;
5747 rtexture_t *viewcolortexture = NULL;
5748 int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5750 // finish any 2D rendering that was queued
5753 if (r_timereport_active)
5754 R_TimeReport("start");
5755 r_textureframe++; // used only by R_GetCurrentTexture
5756 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5758 if(R_CompileShader_CheckStaticParms())
5761 if (!r_drawentities.integer)
5762 r_refdef.scene.numentities = 0;
5763 else if (r_sortentities.integer)
5766 R_AnimCache_ClearCache();
5768 /* adjust for stereo display */
5769 if(R_Stereo_Active())
5771 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);
5772 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5775 if (r_refdef.view.isoverlay)
5777 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5778 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5779 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5780 R_TimeReport("depthclear");
5782 r_refdef.view.showdebug = false;
5784 r_fb.water.enabled = false;
5785 r_fb.water.numwaterplanes = 0;
5787 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5789 r_refdef.view.matrix = originalmatrix;
5795 if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5797 r_refdef.view.matrix = originalmatrix;
5801 r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5802 if (v_isometric.integer && r_refdef.view.ismain)
5803 V_MakeViewIsometric();
5805 r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5807 if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5808 // in sRGB fallback, behave similar to true sRGB: convert this
5809 // value from linear to sRGB
5810 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5812 R_RenderView_UpdateViewVectors();
5814 R_Shadow_UpdateWorldLightSelection();
5816 // this will set up r_fb.rt_screen
5817 R_Bloom_StartFrame();
5819 // apply bloom brightness offset
5821 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5823 // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5826 viewfbo = r_fb.rt_screen->fbo;
5827 viewdepthtexture = r_fb.rt_screen->depthtexture;
5828 viewcolortexture = r_fb.rt_screen->colortexture[0];
5832 viewheight = height;
5835 R_Water_StartFrame();
5838 if (r_timereport_active)
5839 R_TimeReport("viewsetup");
5841 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5843 // clear the whole fbo every frame - otherwise the driver will consider
5844 // it to be an inter-frame texture and stall in multi-gpu configurations
5846 GL_ScissorTest(false);
5847 R_ClearScreen(r_refdef.fogenabled);
5848 if (r_timereport_active)
5849 R_TimeReport("viewclear");
5851 r_refdef.view.clear = true;
5853 r_refdef.view.showdebug = true;
5856 if (r_timereport_active)
5857 R_TimeReport("visibility");
5859 R_AnimCache_CacheVisibleEntities();
5860 if (r_timereport_active)
5861 R_TimeReport("animcache");
5863 R_Shadow_UpdateBounceGridTexture();
5864 if (r_timereport_active && r_shadow_bouncegrid.integer)
5865 R_TimeReport("bouncegrid");
5867 r_fb.water.numwaterplanes = 0;
5868 if (r_fb.water.enabled)
5869 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5871 // for the actual view render we use scissoring a fair amount, so scissor
5872 // test needs to be on
5874 GL_ScissorTest(true);
5875 GL_Scissor(viewx, viewy, viewwidth, viewheight);
5876 R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5877 r_fb.water.numwaterplanes = 0;
5879 // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5880 GL_ScissorTest(false);
5882 R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
5883 if (r_timereport_active)
5884 R_TimeReport("blendview");
5886 r_refdef.view.matrix = originalmatrix;
5890 // go back to 2d rendering
5894 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5896 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5898 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5899 if (r_timereport_active)
5900 R_TimeReport("waterworld");
5903 // don't let sound skip if going slow
5904 if (r_refdef.scene.extraupdate)
5907 R_DrawModelsAddWaterPlanes();
5908 if (r_timereport_active)
5909 R_TimeReport("watermodels");
5911 if (r_fb.water.numwaterplanes)
5913 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5914 if (r_timereport_active)
5915 R_TimeReport("waterscenes");
5919 extern cvar_t cl_locs_show;
5920 static void R_DrawLocs(void);
5921 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5922 static void R_DrawModelDecals(void);
5923 extern cvar_t cl_decals_newsystem;
5924 extern qboolean r_shadow_usingdeferredprepass;
5925 extern int r_shadow_shadowmapatlas_modelshadows_size;
5926 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5928 qboolean shadowmapping = false;
5930 if (r_timereport_active)
5931 R_TimeReport("beginscene");
5933 r_refdef.stats[r_stat_renders]++;
5937 // don't let sound skip if going slow
5938 if (r_refdef.scene.extraupdate)
5941 R_MeshQueue_BeginScene();
5945 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);
5947 if (r_timereport_active)
5948 R_TimeReport("skystartframe");
5950 if (cl.csqc_vidvars.drawworld)
5952 // don't let sound skip if going slow
5953 if (r_refdef.scene.extraupdate)
5956 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5958 r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5959 if (r_timereport_active)
5960 R_TimeReport("worldsky");
5963 if (R_DrawBrushModelsSky() && r_timereport_active)
5964 R_TimeReport("bmodelsky");
5966 if (skyrendermasked && skyrenderlater)
5968 // we have to force off the water clipping plane while rendering sky
5969 R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5971 R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5972 if (r_timereport_active)
5973 R_TimeReport("sky");
5977 // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5978 r_shadow_viewfbo = viewfbo;
5979 r_shadow_viewdepthtexture = viewdepthtexture;
5980 r_shadow_viewcolortexture = viewcolortexture;
5981 r_shadow_viewx = viewx;
5982 r_shadow_viewy = viewy;
5983 r_shadow_viewwidth = viewwidth;
5984 r_shadow_viewheight = viewheight;
5986 R_Shadow_PrepareModelShadows();
5987 R_Shadow_PrepareLights();
5988 if (r_timereport_active)
5989 R_TimeReport("preparelights");
5991 // render all the shadowmaps that will be used for this view
5992 shadowmapping = R_Shadow_ShadowMappingEnabled();
5993 if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
5995 R_Shadow_DrawShadowMaps();
5996 if (r_timereport_active)
5997 R_TimeReport("shadowmaps");
6000 // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
6001 if (r_shadow_usingdeferredprepass)
6002 R_Shadow_DrawPrepass();
6004 // now we begin the forward pass of the view render
6005 if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
6007 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
6008 if (r_timereport_active)
6009 R_TimeReport("worlddepth");
6011 if (r_depthfirst.integer >= 2)
6013 R_DrawModelsDepth();
6014 if (r_timereport_active)
6015 R_TimeReport("modeldepth");
6018 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
6020 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
6021 if (r_timereport_active)
6022 R_TimeReport("world");
6025 // don't let sound skip if going slow
6026 if (r_refdef.scene.extraupdate)
6030 if (r_timereport_active)
6031 R_TimeReport("models");
6033 // don't let sound skip if going slow
6034 if (r_refdef.scene.extraupdate)
6037 if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && !r_shadows_drawafterrtlighting.integer && r_refdef.scene.lightmapintensity > 0)
6039 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6040 R_Shadow_DrawModelShadows();
6041 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6042 // don't let sound skip if going slow
6043 if (r_refdef.scene.extraupdate)
6047 if (!r_shadow_usingdeferredprepass)
6049 R_Shadow_DrawLights();
6050 if (r_timereport_active)
6051 R_TimeReport("rtlights");
6054 // don't let sound skip if going slow
6055 if (r_refdef.scene.extraupdate)
6058 if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && r_shadows_drawafterrtlighting.integer && r_refdef.scene.lightmapintensity > 0)
6060 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6061 R_Shadow_DrawModelShadows();
6062 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6063 // don't let sound skip if going slow
6064 if (r_refdef.scene.extraupdate)
6068 if (cl.csqc_vidvars.drawworld)
6070 if (cl_decals_newsystem.integer)
6072 R_DrawModelDecals();
6073 if (r_timereport_active)
6074 R_TimeReport("modeldecals");
6079 if (r_timereport_active)
6080 R_TimeReport("decals");
6084 if (r_timereport_active)
6085 R_TimeReport("particles");
6088 if (r_timereport_active)
6089 R_TimeReport("explosions");
6092 if (r_refdef.view.showdebug)
6094 if (cl_locs_show.integer)
6097 if (r_timereport_active)
6098 R_TimeReport("showlocs");
6101 if (r_drawportals.integer)
6104 if (r_timereport_active)
6105 R_TimeReport("portals");
6108 if (r_showbboxes_client.value > 0)
6110 R_DrawEntityBBoxes(CLVM_prog);
6111 if (r_timereport_active)
6112 R_TimeReport("clbboxes");
6114 if (r_showbboxes.value > 0)
6116 R_DrawEntityBBoxes(SVVM_prog);
6117 if (r_timereport_active)
6118 R_TimeReport("svbboxes");
6122 if (r_transparent.integer)
6124 R_MeshQueue_RenderTransparent();
6125 if (r_timereport_active)
6126 R_TimeReport("drawtrans");
6129 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))
6131 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
6132 if (r_timereport_active)
6133 R_TimeReport("worlddebug");
6134 R_DrawModelsDebug();
6135 if (r_timereport_active)
6136 R_TimeReport("modeldebug");
6139 if (cl.csqc_vidvars.drawworld)
6141 R_Shadow_DrawCoronas();
6142 if (r_timereport_active)
6143 R_TimeReport("coronas");
6146 // don't let sound skip if going slow
6147 if (r_refdef.scene.extraupdate)
6151 static const unsigned short bboxelements[36] =
6161 #define BBOXEDGES 13
6162 static const float bboxedges[BBOXEDGES][6] =
6165 { 0, 0, 0, 1, 1, 1 },
6167 { 0, 0, 0, 0, 1, 0 },
6168 { 0, 0, 0, 1, 0, 0 },
6169 { 0, 1, 0, 1, 1, 0 },
6170 { 1, 0, 0, 1, 1, 0 },
6172 { 0, 0, 1, 0, 1, 1 },
6173 { 0, 0, 1, 1, 0, 1 },
6174 { 0, 1, 1, 1, 1, 1 },
6175 { 1, 0, 1, 1, 1, 1 },
6177 { 0, 0, 0, 0, 0, 1 },
6178 { 1, 0, 0, 1, 0, 1 },
6179 { 0, 1, 0, 0, 1, 1 },
6180 { 1, 1, 0, 1, 1, 1 },
6183 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6185 int numvertices = BBOXEDGES * 8;
6186 float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6187 int numtriangles = BBOXEDGES * 12;
6188 unsigned short elements[BBOXEDGES * 36];
6190 float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6192 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6194 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6195 GL_DepthMask(false);
6196 GL_DepthRange(0, 1);
6197 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6199 for (edge = 0; edge < BBOXEDGES; edge++)
6201 for (i = 0; i < 3; i++)
6203 edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6204 edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6206 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6207 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6208 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6209 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6210 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6211 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6212 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6213 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6214 for (i = 0; i < 36; i++)
6215 elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6217 R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6218 if (r_refdef.fogenabled)
6220 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6222 f1 = RSurf_FogVertex(v);
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;
6229 R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6230 R_Mesh_ResetTextureState();
6231 R_SetupShader_Generic_NoTexture(false, false);
6232 R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6235 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6237 // hacky overloading of the parameters
6238 prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6241 prvm_edict_t *edict;
6243 GL_CullFace(GL_NONE);
6244 R_SetupShader_Generic_NoTexture(false, false);
6246 for (i = 0;i < numsurfaces;i++)
6248 edict = PRVM_EDICT_NUM(surfacelist[i]);
6249 switch ((int)PRVM_serveredictfloat(edict, solid))
6251 case SOLID_NOT: Vector4Set(color, 1, 1, 1, 0.05);break;
6252 case SOLID_TRIGGER: Vector4Set(color, 1, 0, 1, 0.10);break;
6253 case SOLID_BBOX: Vector4Set(color, 0, 1, 0, 0.10);break;
6254 case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6255 case SOLID_BSP: Vector4Set(color, 0, 0, 1, 0.05);break;
6256 case SOLID_CORPSE: Vector4Set(color, 1, 0.5, 0, 0.05);break;
6257 default: Vector4Set(color, 0, 0, 0, 0.50);break;
6259 if (prog == CLVM_prog)
6260 color[3] *= r_showbboxes_client.value;
6262 color[3] *= r_showbboxes.value;
6263 color[3] = bound(0, color[3], 1);
6264 GL_DepthTest(!r_showdisabledepthtest.integer);
6265 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6269 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6272 prvm_edict_t *edict;
6278 for (i = 0; i < prog->num_edicts; i++)
6280 edict = PRVM_EDICT_NUM(i);
6281 if (edict->priv.server->free)
6283 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6284 if (PRVM_serveredictedict(edict, tag_entity) != 0)
6286 if (PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6288 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6289 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6293 static const int nomodelelement3i[24] =
6305 static const unsigned short nomodelelement3s[24] =
6317 static const float nomodelvertex3f[6*3] =
6327 static const float nomodelcolor4f[6*4] =
6329 0.0f, 0.0f, 0.5f, 1.0f,
6330 0.0f, 0.0f, 0.5f, 1.0f,
6331 0.0f, 0.5f, 0.0f, 1.0f,
6332 0.0f, 0.5f, 0.0f, 1.0f,
6333 0.5f, 0.0f, 0.0f, 1.0f,
6334 0.5f, 0.0f, 0.0f, 1.0f
6337 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6343 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);
6345 // this is only called once per entity so numsurfaces is always 1, and
6346 // surfacelist is always {0}, so this code does not handle batches
6348 if (rsurface.ent_flags & RENDER_ADDITIVE)
6350 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6351 GL_DepthMask(false);
6353 else if (ent->alpha < 1)
6355 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6356 GL_DepthMask(false);
6360 GL_BlendFunc(GL_ONE, GL_ZERO);
6363 GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6364 GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6365 GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6366 GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6367 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6368 for (i = 0, c = color4f;i < 6;i++, c += 4)
6370 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6371 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6372 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6375 if (r_refdef.fogenabled)
6377 for (i = 0, c = color4f;i < 6;i++, c += 4)
6379 f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6381 c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6382 c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6383 c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6386 // R_Mesh_ResetTextureState();
6387 R_SetupShader_Generic_NoTexture(false, false);
6388 R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6389 R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6392 void R_DrawNoModel(entity_render_t *ent)
6395 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6396 if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6397 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6399 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6402 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6404 vec3_t right1, right2, diff, normal;
6406 VectorSubtract (org2, org1, normal);
6408 // calculate 'right' vector for start
6409 VectorSubtract (r_refdef.view.origin, org1, diff);
6410 CrossProduct (normal, diff, right1);
6411 VectorNormalize (right1);
6413 // calculate 'right' vector for end
6414 VectorSubtract (r_refdef.view.origin, org2, diff);
6415 CrossProduct (normal, diff, right2);
6416 VectorNormalize (right2);
6418 vert[ 0] = org1[0] + width * right1[0];
6419 vert[ 1] = org1[1] + width * right1[1];
6420 vert[ 2] = org1[2] + width * right1[2];
6421 vert[ 3] = org1[0] - width * right1[0];
6422 vert[ 4] = org1[1] - width * right1[1];
6423 vert[ 5] = org1[2] - width * right1[2];
6424 vert[ 6] = org2[0] - width * right2[0];
6425 vert[ 7] = org2[1] - width * right2[1];
6426 vert[ 8] = org2[2] - width * right2[2];
6427 vert[ 9] = org2[0] + width * right2[0];
6428 vert[10] = org2[1] + width * right2[1];
6429 vert[11] = org2[2] + width * right2[2];
6432 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)
6434 vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6435 vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6436 vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6437 vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6438 vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6439 vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6440 vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6441 vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6442 vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6443 vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6444 vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6445 vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6448 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6453 VectorSet(v, x, y, z);
6454 for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6455 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6457 if (i == mesh->numvertices)
6459 if (mesh->numvertices < mesh->maxvertices)
6461 VectorCopy(v, vertex3f);
6462 mesh->numvertices++;
6464 return mesh->numvertices;
6470 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6474 element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6475 element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6476 e = mesh->element3i + mesh->numtriangles * 3;
6477 for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6479 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6480 if (mesh->numtriangles < mesh->maxtriangles)
6485 mesh->numtriangles++;
6487 element[1] = element[2];
6491 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6495 element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6496 element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6497 e = mesh->element3i + mesh->numtriangles * 3;
6498 for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6500 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6501 if (mesh->numtriangles < mesh->maxtriangles)
6506 mesh->numtriangles++;
6508 element[1] = element[2];
6512 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6513 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6515 int planenum, planenum2;
6518 mplane_t *plane, *plane2;
6520 double temppoints[2][256*3];
6521 // figure out how large a bounding box we need to properly compute this brush
6523 for (w = 0;w < numplanes;w++)
6524 maxdist = max(maxdist, fabs(planes[w].dist));
6525 // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6526 maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6527 for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6531 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6532 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6534 if (planenum2 == planenum)
6536 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);
6539 if (tempnumpoints < 3)
6541 // generate elements forming a triangle fan for this polygon
6542 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6546 static void R_Texture_AddLayer(texture_t *t, qboolean depthmask, int blendfunc1, int blendfunc2, texturelayertype_t type, rtexture_t *texture, const matrix4x4_t *matrix, float r, float g, float b, float a)
6548 texturelayer_t *layer;
6549 layer = t->currentlayers + t->currentnumlayers++;
6551 layer->depthmask = depthmask;
6552 layer->blendfunc1 = blendfunc1;
6553 layer->blendfunc2 = blendfunc2;
6554 layer->texture = texture;
6555 layer->texmatrix = *matrix;
6556 layer->color[0] = r;
6557 layer->color[1] = g;
6558 layer->color[2] = b;
6559 layer->color[3] = a;
6562 static qboolean R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6564 if(parms[0] == 0 && parms[1] == 0)
6566 if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6567 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6572 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6575 index = parms[2] + rsurface.shadertime * parms[3];
6576 index -= floor(index);
6577 switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6580 case Q3WAVEFUNC_NONE:
6581 case Q3WAVEFUNC_NOISE:
6582 case Q3WAVEFUNC_COUNT:
6585 case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6586 case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6587 case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6588 case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6589 case Q3WAVEFUNC_TRIANGLE:
6591 f = index - floor(index);
6604 f = parms[0] + parms[1] * f;
6605 if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6606 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6610 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6617 matrix4x4_t matrix, temp;
6618 // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6619 // it's better to have one huge fixup every 9 hours than gradual
6620 // degradation over time which looks consistently bad after many hours.
6622 // tcmod scroll in particular suffers from this degradation which can't be
6623 // effectively worked around even with floor() tricks because we don't
6624 // know if tcmod scroll is the last tcmod being applied, and for clampmap
6625 // a workaround involving floor() would be incorrect anyway...
6626 shadertime = rsurface.shadertime;
6627 if (shadertime >= 32768.0f)
6628 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6629 switch(tcmod->tcmod)
6633 if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6634 matrix = r_waterscrollmatrix;
6636 matrix = identitymatrix;
6638 case Q3TCMOD_ENTITYTRANSLATE:
6639 // this is used in Q3 to allow the gamecode to control texcoord
6640 // scrolling on the entity, which is not supported in darkplaces yet.
6641 Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6643 case Q3TCMOD_ROTATE:
6644 Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6645 Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6646 Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6649 Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6651 case Q3TCMOD_SCROLL:
6652 // this particular tcmod is a "bug for bug" compatible one with regards to
6653 // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6654 // specifically did the wrapping and so we must mimic that...
6655 offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6656 offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6657 Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6659 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6660 w = (int) tcmod->parms[0];
6661 h = (int) tcmod->parms[1];
6662 f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6664 idx = (int) floor(f * w * h);
6665 Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6667 case Q3TCMOD_STRETCH:
6668 f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6669 Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6671 case Q3TCMOD_TRANSFORM:
6672 VectorSet(tcmat + 0, tcmod->parms[0], tcmod->parms[1], 0);
6673 VectorSet(tcmat + 3, tcmod->parms[2], tcmod->parms[3], 0);
6674 VectorSet(tcmat + 6, 0 , 0 , 1);
6675 VectorSet(tcmat + 9, tcmod->parms[4], tcmod->parms[5], 0);
6676 Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6678 case Q3TCMOD_TURBULENT:
6679 // this is handled in the RSurf_PrepareVertices function
6680 matrix = identitymatrix;
6684 Matrix4x4_Concat(texmatrix, &matrix, &temp);
6687 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6689 int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6690 char name[MAX_QPATH];
6691 skinframe_t *skinframe;
6692 unsigned char pixels[296*194];
6693 strlcpy(cache->name, skinname, sizeof(cache->name));
6694 dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6695 if (developer_loading.integer)
6696 Con_Printf("loading %s\n", name);
6697 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6698 if (!skinframe || !skinframe->base)
6701 fs_offset_t filesize;
6703 f = FS_LoadFile(name, tempmempool, true, &filesize);
6706 if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6707 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6711 cache->skinframe = skinframe;
6714 texture_t *R_GetCurrentTexture(texture_t *t)
6717 const entity_render_t *ent = rsurface.entity;
6718 dp_model_t *model = ent->model; // when calling this, ent must not be NULL
6719 q3shaderinfo_layer_tcmod_t *tcmod;
6720 float specularscale = 0.0f;
6722 if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6723 return t->currentframe;
6724 t->update_lastrenderframe = r_textureframe;
6725 t->update_lastrenderentity = (void *)ent;
6727 if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6728 t->camera_entity = ent->entitynumber;
6730 t->camera_entity = 0;
6732 // switch to an alternate material if this is a q1bsp animated material
6734 texture_t *texture = t;
6735 int s = rsurface.ent_skinnum;
6736 if ((unsigned int)s >= (unsigned int)model->numskins)
6738 if (model->skinscenes)
6740 if (model->skinscenes[s].framecount > 1)
6741 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6743 s = model->skinscenes[s].firstframe;
6746 t = t + s * model->num_surfaces;
6749 // use an alternate animation if the entity's frame is not 0,
6750 // and only if the texture has an alternate animation
6751 if (t->animated == 2) // q2bsp
6752 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6753 else if (rsurface.ent_alttextures && t->anim_total[1])
6754 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6756 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6758 texture->currentframe = t;
6761 // update currentskinframe to be a qw skin or animation frame
6762 if (rsurface.ent_qwskin >= 0)
6764 i = rsurface.ent_qwskin;
6765 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6767 r_qwskincache_size = cl.maxclients;
6769 Mem_Free(r_qwskincache);
6770 r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6772 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6773 R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6774 t->currentskinframe = r_qwskincache[i].skinframe;
6775 if (t->materialshaderpass && t->currentskinframe == NULL)
6776 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6778 else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6779 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6780 if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6781 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6783 t->currentmaterialflags = t->basematerialflags;
6784 t->currentalpha = rsurface.entity->alpha * t->basealpha;
6785 if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_novis.integer || r_trippy.integer))
6786 t->currentalpha *= r_wateralpha.value;
6787 if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6788 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6789 if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6790 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6792 // decide on which type of lighting to use for this surface
6793 if (rsurface.entity->render_modellight_forced)
6794 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6795 if (rsurface.entity->render_rtlight_disabled)
6796 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6797 if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6799 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6800 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT;
6801 for (q = 0; q < 3; q++)
6803 t->render_glowmod[q] = rsurface.entity->glowmod[q];
6804 t->render_modellight_lightdir[q] = q == 2;
6805 t->render_modellight_ambient[q] = 1;
6806 t->render_modellight_diffuse[q] = 0;
6807 t->render_modellight_specular[q] = 0;
6808 t->render_lightmap_ambient[q] = 0;
6809 t->render_lightmap_diffuse[q] = 0;
6810 t->render_lightmap_specular[q] = 0;
6811 t->render_rtlight_diffuse[q] = 0;
6812 t->render_rtlight_specular[q] = 0;
6815 else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6817 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6818 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT;
6819 for (q = 0; q < 3; q++)
6821 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6822 t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6823 t->render_modellight_lightdir[q] = q == 2;
6824 t->render_modellight_diffuse[q] = 0;
6825 t->render_modellight_specular[q] = 0;
6826 t->render_lightmap_ambient[q] = 0;
6827 t->render_lightmap_diffuse[q] = 0;
6828 t->render_lightmap_specular[q] = 0;
6829 t->render_rtlight_diffuse[q] = 0;
6830 t->render_rtlight_specular[q] = 0;
6833 else if (FAKELIGHT_ENABLED)
6835 // no modellight if using fakelight for the map
6836 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_NORTLIGHT) & ~(MATERIALFLAG_MODELLIGHT);
6837 for (q = 0; q < 3; q++)
6839 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6840 t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6841 t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6842 t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6843 t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6844 t->render_lightmap_ambient[q] = 0;
6845 t->render_lightmap_diffuse[q] = 0;
6846 t->render_lightmap_specular[q] = 0;
6847 t->render_rtlight_diffuse[q] = 0;
6848 t->render_rtlight_specular[q] = 0;
6851 else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6853 // ambient + single direction light (modellight)
6854 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6855 for (q = 0; q < 3; q++)
6857 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6858 t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6859 t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6860 t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6861 t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6862 t->render_lightmap_ambient[q] = 0;
6863 t->render_lightmap_diffuse[q] = 0;
6864 t->render_lightmap_specular[q] = 0;
6865 t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6866 t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6871 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6872 for (q = 0; q < 3; q++)
6874 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6875 t->render_modellight_lightdir[q] = q == 2;
6876 t->render_modellight_ambient[q] = 0;
6877 t->render_modellight_diffuse[q] = 0;
6878 t->render_modellight_specular[q] = 0;
6879 t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6880 t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6881 t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6882 t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6883 t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6887 if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6889 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6890 // attribute, we punt it to the lightmap path and hope for the best,
6891 // but lighting doesn't work.
6893 // FIXME: this is fine for effects but CSQC polygons should be subject
6895 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6896 for (q = 0; q < 3; q++)
6898 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6899 t->render_modellight_lightdir[q] = q == 2;
6900 t->render_modellight_ambient[q] = 0;
6901 t->render_modellight_diffuse[q] = 0;
6902 t->render_modellight_specular[q] = 0;
6903 t->render_lightmap_ambient[q] = 0;
6904 t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6905 t->render_lightmap_specular[q] = 0;
6906 t->render_rtlight_diffuse[q] = 0;
6907 t->render_rtlight_specular[q] = 0;
6911 for (q = 0; q < 3; q++)
6913 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6914 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6917 if (rsurface.ent_flags & RENDER_ADDITIVE)
6918 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6919 else if (t->currentalpha < 1)
6920 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6921 // LordHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6922 if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6923 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6924 if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6925 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6926 if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6927 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6928 if (t->backgroundshaderpass)
6929 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6930 if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6932 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6933 t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6936 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6937 if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6939 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6940 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6942 if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6943 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6945 // there is no tcmod
6946 if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6948 t->currenttexmatrix = r_waterscrollmatrix;
6949 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6951 else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6953 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6954 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6957 if (t->materialshaderpass)
6958 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6959 R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6961 t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6962 if (t->currentskinframe->qpixels)
6963 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6964 t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6965 if (!t->basetexture)
6966 t->basetexture = r_texture_notexture;
6967 t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6968 t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6969 t->nmaptexture = t->currentskinframe->nmap;
6970 if (!t->nmaptexture)
6971 t->nmaptexture = r_texture_blanknormalmap;
6972 t->glosstexture = r_texture_black;
6973 t->glowtexture = t->currentskinframe->glow;
6974 t->fogtexture = t->currentskinframe->fog;
6975 t->reflectmasktexture = t->currentskinframe->reflect;
6976 if (t->backgroundshaderpass)
6978 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6979 R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6980 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6981 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6982 t->backgroundglosstexture = r_texture_black;
6983 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6984 if (!t->backgroundnmaptexture)
6985 t->backgroundnmaptexture = r_texture_blanknormalmap;
6986 // make sure that if glow is going to be used, both textures are not NULL
6987 if (!t->backgroundglowtexture && t->glowtexture)
6988 t->backgroundglowtexture = r_texture_black;
6989 if (!t->glowtexture && t->backgroundglowtexture)
6990 t->glowtexture = r_texture_black;
6994 t->backgroundbasetexture = r_texture_white;
6995 t->backgroundnmaptexture = r_texture_blanknormalmap;
6996 t->backgroundglosstexture = r_texture_black;
6997 t->backgroundglowtexture = NULL;
6999 t->specularpower = r_shadow_glossexponent.value;
7000 // TODO: store reference values for these in the texture?
7001 if (r_shadow_gloss.integer > 0)
7003 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
7005 if (r_shadow_glossintensity.value > 0)
7007 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
7008 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
7009 specularscale = r_shadow_glossintensity.value;
7012 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
7014 t->glosstexture = r_texture_white;
7015 t->backgroundglosstexture = r_texture_white;
7016 specularscale = r_shadow_gloss2intensity.value;
7017 t->specularpower = r_shadow_gloss2exponent.value;
7020 specularscale *= t->specularscalemod;
7021 t->specularpower *= t->specularpowermod;
7023 // lightmaps mode looks bad with dlights using actual texturing, so turn
7024 // off the colormap and glossmap, but leave the normalmap on as it still
7025 // accurately represents the shading involved
7026 if (gl_lightmaps.integer)
7028 t->basetexture = r_texture_grey128;
7029 t->pantstexture = r_texture_black;
7030 t->shirttexture = r_texture_black;
7031 if (gl_lightmaps.integer < 2)
7032 t->nmaptexture = r_texture_blanknormalmap;
7033 t->glosstexture = r_texture_black;
7034 t->glowtexture = NULL;
7035 t->fogtexture = NULL;
7036 t->reflectmasktexture = NULL;
7037 t->backgroundbasetexture = NULL;
7038 if (gl_lightmaps.integer < 2)
7039 t->backgroundnmaptexture = r_texture_blanknormalmap;
7040 t->backgroundglosstexture = r_texture_black;
7041 t->backgroundglowtexture = NULL;
7043 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
7046 if (specularscale != 1.0f)
7048 for (q = 0; q < 3; q++)
7050 t->render_modellight_specular[q] *= specularscale;
7051 t->render_lightmap_specular[q] *= specularscale;
7052 t->render_rtlight_specular[q] *= specularscale;
7056 t->currentnumlayers = 0;
7057 if (t->currentmaterialflags & MATERIALFLAG_WALL)
7059 int blendfunc1, blendfunc2;
7061 if (t->currentmaterialflags & MATERIALFLAG_ADD)
7063 blendfunc1 = GL_SRC_ALPHA;
7064 blendfunc2 = GL_ONE;
7066 else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
7068 blendfunc1 = GL_SRC_ALPHA;
7069 blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
7071 else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
7073 blendfunc1 = t->customblendfunc[0];
7074 blendfunc2 = t->customblendfunc[1];
7078 blendfunc1 = GL_ONE;
7079 blendfunc2 = GL_ZERO;
7081 depthmask = !(t->currentmaterialflags & MATERIALFLAG_BLENDED);
7082 if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
7084 // basic lit geometry
7085 R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE, t->basetexture, &t->currenttexmatrix, 2, 2, 2, t->currentalpha);
7086 // add pants/shirt if needed
7087 if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7088 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->pantstexture, &t->currenttexmatrix, 2 * t->render_colormap_pants[0], 2 * t->render_colormap_pants[1], 2 * t->render_colormap_pants[2], t->currentalpha);
7089 if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7090 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->shirttexture, &t->currenttexmatrix, 2 * t->render_colormap_shirt[0], 2 * t->render_colormap_shirt[1], 2 * t->render_colormap_shirt[2], t->currentalpha);
7094 // basic lit geometry
7095 R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE, t->basetexture, &t->currenttexmatrix, t->render_lightmap_diffuse[0], t->render_lightmap_diffuse[1], t->render_lightmap_diffuse[2], t->currentalpha);
7096 // add pants/shirt if needed
7097 if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7098 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->pantstexture, &t->currenttexmatrix, t->render_colormap_pants[0] * t->render_lightmap_diffuse[0], t->render_colormap_pants[1] * t->render_lightmap_diffuse[1], t->render_colormap_pants[2] * t->render_lightmap_diffuse[2], t->currentalpha);
7099 if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7100 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->shirttexture, &t->currenttexmatrix, t->render_colormap_shirt[0] * t->render_lightmap_diffuse[0], t->render_colormap_shirt[1] * t->render_lightmap_diffuse[1], t->render_colormap_shirt[2] * t->render_lightmap_diffuse[2], t->currentalpha);
7101 // now add ambient passes if needed
7102 if (VectorLength2(t->render_lightmap_ambient) >= (1.0f/1048576.0f))
7104 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->basetexture, &t->currenttexmatrix, t->render_lightmap_ambient[0], t->render_lightmap_ambient[1], t->render_lightmap_ambient[2], t->currentalpha);
7105 if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7106 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->pantstexture, &t->currenttexmatrix, t->render_colormap_pants[0] * t->render_lightmap_ambient[0], t->render_colormap_pants[1] * t->render_lightmap_ambient[1], t->render_colormap_pants[2] * t->render_lightmap_ambient[2], t->currentalpha);
7107 if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7108 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->shirttexture, &t->currenttexmatrix, t->render_colormap_shirt[0] * t->render_lightmap_ambient[0], t->render_colormap_shirt[1] * t->render_lightmap_ambient[1], t->render_colormap_shirt[2] * t->render_lightmap_ambient[2], t->currentalpha);
7111 if (t->glowtexture != NULL && !gl_lightmaps.integer)
7112 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->glowtexture, &t->currenttexmatrix, t->render_glowmod[0], t->render_glowmod[1], t->render_glowmod[2], t->currentalpha);
7113 if (r_refdef.fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD))
7115 // if this is opaque use alpha blend which will darken the earlier
7118 // if this is an alpha blended material, all the earlier passes
7119 // were darkened by fog already, so we only need to add the fog
7120 // color ontop through the fog mask texture
7122 // if this is an additive blended material, all the earlier passes
7123 // were darkened by fog already, and we should not add fog color
7124 // (because the background was not darkened, there is no fog color
7125 // that was lost behind it).
7126 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, (t->currentmaterialflags & MATERIALFLAG_BLENDED) ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA, TEXTURELAYERTYPE_FOG, t->fogtexture, &t->currenttexmatrix, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], t->currentalpha);
7133 rsurfacestate_t rsurface;
7135 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
7137 dp_model_t *model = ent->model;
7138 //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
7140 rsurface.entity = (entity_render_t *)ent;
7141 rsurface.skeleton = ent->skeleton;
7142 memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
7143 rsurface.ent_skinnum = ent->skinnum;
7144 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;
7145 rsurface.ent_flags = ent->flags;
7146 if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
7147 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
7148 rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
7149 rsurface.matrix = ent->matrix;
7150 rsurface.inversematrix = ent->inversematrix;
7151 rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7152 rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7153 R_EntityMatrix(&rsurface.matrix);
7154 Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7155 Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7156 rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
7157 rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7158 rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7159 rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7160 memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
7161 rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
7162 rsurface.basepolygonfactor = r_refdef.polygonfactor;
7163 rsurface.basepolygonoffset = r_refdef.polygonoffset;
7164 if (ent->model->brush.submodel && !prepass)
7166 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
7167 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
7169 // if the animcache code decided it should use the shader path, skip the deform step
7170 rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
7171 rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
7172 rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
7173 rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
7174 rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
7175 if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
7177 if (ent->animcache_vertex3f)
7179 r_refdef.stats[r_stat_batch_entitycache_count]++;
7180 r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
7181 r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
7182 r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
7183 rsurface.modelvertex3f = ent->animcache_vertex3f;
7184 rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
7185 rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
7186 rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
7187 rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
7188 rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
7189 rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
7190 rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
7191 rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
7192 rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
7193 rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
7194 rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
7195 rsurface.modelvertexmesh = ent->animcache_vertexmesh;
7196 rsurface.modelvertexmesh_vertexbuffer = ent->animcache_vertexmesh_vertexbuffer;
7197 rsurface.modelvertexmesh_bufferoffset = ent->animcache_vertexmesh_bufferoffset;
7199 else if (wanttangents)
7201 r_refdef.stats[r_stat_batch_entityanimate_count]++;
7202 r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7203 r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7204 r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7205 rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7206 rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7207 rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7208 rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7209 model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
7210 rsurface.modelvertexmesh = NULL;
7211 rsurface.modelvertexmesh_vertexbuffer = NULL;
7212 rsurface.modelvertexmesh_bufferoffset = 0;
7213 rsurface.modelvertex3f_vertexbuffer = NULL;
7214 rsurface.modelvertex3f_bufferoffset = 0;
7215 rsurface.modelvertex3f_vertexbuffer = 0;
7216 rsurface.modelvertex3f_bufferoffset = 0;
7217 rsurface.modelsvector3f_vertexbuffer = 0;
7218 rsurface.modelsvector3f_bufferoffset = 0;
7219 rsurface.modeltvector3f_vertexbuffer = 0;
7220 rsurface.modeltvector3f_bufferoffset = 0;
7221 rsurface.modelnormal3f_vertexbuffer = 0;
7222 rsurface.modelnormal3f_bufferoffset = 0;
7224 else if (wantnormals)
7226 r_refdef.stats[r_stat_batch_entityanimate_count]++;
7227 r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7228 r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7229 r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7230 rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7231 rsurface.modelsvector3f = NULL;
7232 rsurface.modeltvector3f = NULL;
7233 rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7234 model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
7235 rsurface.modelvertexmesh = NULL;
7236 rsurface.modelvertexmesh_vertexbuffer = NULL;
7237 rsurface.modelvertexmesh_bufferoffset = 0;
7238 rsurface.modelvertex3f_vertexbuffer = NULL;
7239 rsurface.modelvertex3f_bufferoffset = 0;
7240 rsurface.modelvertex3f_vertexbuffer = 0;
7241 rsurface.modelvertex3f_bufferoffset = 0;
7242 rsurface.modelsvector3f_vertexbuffer = 0;
7243 rsurface.modelsvector3f_bufferoffset = 0;
7244 rsurface.modeltvector3f_vertexbuffer = 0;
7245 rsurface.modeltvector3f_bufferoffset = 0;
7246 rsurface.modelnormal3f_vertexbuffer = 0;
7247 rsurface.modelnormal3f_bufferoffset = 0;
7251 r_refdef.stats[r_stat_batch_entityanimate_count]++;
7252 r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7253 r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7254 r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7255 rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7256 rsurface.modelsvector3f = NULL;
7257 rsurface.modeltvector3f = NULL;
7258 rsurface.modelnormal3f = NULL;
7259 model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7260 rsurface.modelvertexmesh = NULL;
7261 rsurface.modelvertexmesh_vertexbuffer = NULL;
7262 rsurface.modelvertexmesh_bufferoffset = 0;
7263 rsurface.modelvertex3f_vertexbuffer = NULL;
7264 rsurface.modelvertex3f_bufferoffset = 0;
7265 rsurface.modelvertex3f_vertexbuffer = 0;
7266 rsurface.modelvertex3f_bufferoffset = 0;
7267 rsurface.modelsvector3f_vertexbuffer = 0;
7268 rsurface.modelsvector3f_bufferoffset = 0;
7269 rsurface.modeltvector3f_vertexbuffer = 0;
7270 rsurface.modeltvector3f_bufferoffset = 0;
7271 rsurface.modelnormal3f_vertexbuffer = 0;
7272 rsurface.modelnormal3f_bufferoffset = 0;
7274 rsurface.modelgeneratedvertex = true;
7278 if (rsurface.entityskeletaltransform3x4)
7280 r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7281 r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7282 r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7283 r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7287 r_refdef.stats[r_stat_batch_entitystatic_count]++;
7288 r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7289 r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7290 r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7292 rsurface.modelvertex3f = model->surfmesh.data_vertex3f;
7293 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7294 rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
7295 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7296 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7297 rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f;
7298 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7299 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7300 rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f;
7301 rsurface.modelnormal3f = model->surfmesh.data_normal3f;
7302 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7303 rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f;
7304 rsurface.modelvertexmesh = model->surfmesh.data_vertexmesh;
7305 rsurface.modelvertexmesh_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7306 rsurface.modelvertexmesh_bufferoffset = model->surfmesh.vbooffset_vertex3f;
7307 rsurface.modelgeneratedvertex = false;
7309 rsurface.modellightmapcolor4f = model->surfmesh.data_lightmapcolor4f;
7310 rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7311 rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f;
7312 rsurface.modeltexcoordtexture2f = model->surfmesh.data_texcoordtexture2f;
7313 rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7314 rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f;
7315 rsurface.modeltexcoordlightmap2f = model->surfmesh.data_texcoordlightmap2f;
7316 rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7317 rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
7318 rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7319 rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7320 rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.vbooffset_skeletalindex4ub;
7321 rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7322 rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7323 rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.vbooffset_skeletalweight4ub;
7324 rsurface.modelelement3i = model->surfmesh.data_element3i;
7325 rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7326 rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7327 rsurface.modelelement3s = model->surfmesh.data_element3s;
7328 rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7329 rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7330 rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7331 rsurface.modelnumvertices = model->surfmesh.num_vertices;
7332 rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7333 rsurface.modelsurfaces = model->data_surfaces;
7334 rsurface.batchgeneratedvertex = false;
7335 rsurface.batchfirstvertex = 0;
7336 rsurface.batchnumvertices = 0;
7337 rsurface.batchfirsttriangle = 0;
7338 rsurface.batchnumtriangles = 0;
7339 rsurface.batchvertex3f = NULL;
7340 rsurface.batchvertex3f_vertexbuffer = NULL;
7341 rsurface.batchvertex3f_bufferoffset = 0;
7342 rsurface.batchsvector3f = NULL;
7343 rsurface.batchsvector3f_vertexbuffer = NULL;
7344 rsurface.batchsvector3f_bufferoffset = 0;
7345 rsurface.batchtvector3f = NULL;
7346 rsurface.batchtvector3f_vertexbuffer = NULL;
7347 rsurface.batchtvector3f_bufferoffset = 0;
7348 rsurface.batchnormal3f = NULL;
7349 rsurface.batchnormal3f_vertexbuffer = NULL;
7350 rsurface.batchnormal3f_bufferoffset = 0;
7351 rsurface.batchlightmapcolor4f = NULL;
7352 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7353 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7354 rsurface.batchtexcoordtexture2f = NULL;
7355 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7356 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7357 rsurface.batchtexcoordlightmap2f = NULL;
7358 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7359 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7360 rsurface.batchskeletalindex4ub = NULL;
7361 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7362 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7363 rsurface.batchskeletalweight4ub = NULL;
7364 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7365 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7366 rsurface.batchvertexmesh = NULL;
7367 rsurface.batchvertexmesh_vertexbuffer = NULL;
7368 rsurface.batchvertexmesh_bufferoffset = 0;
7369 rsurface.batchelement3i = NULL;
7370 rsurface.batchelement3i_indexbuffer = NULL;
7371 rsurface.batchelement3i_bufferoffset = 0;
7372 rsurface.batchelement3s = NULL;
7373 rsurface.batchelement3s_indexbuffer = NULL;
7374 rsurface.batchelement3s_bufferoffset = 0;
7375 rsurface.forcecurrenttextureupdate = false;
7378 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)
7380 rsurface.entity = r_refdef.scene.worldentity;
7381 rsurface.skeleton = NULL;
7382 rsurface.ent_skinnum = 0;
7383 rsurface.ent_qwskin = -1;
7384 rsurface.ent_flags = entflags;
7385 rsurface.shadertime = r_refdef.scene.time - shadertime;
7386 rsurface.modelnumvertices = numvertices;
7387 rsurface.modelnumtriangles = numtriangles;
7388 rsurface.matrix = *matrix;
7389 rsurface.inversematrix = *inversematrix;
7390 rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7391 rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7392 R_EntityMatrix(&rsurface.matrix);
7393 Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7394 Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7395 rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7396 rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7397 rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7398 rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7399 memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7400 rsurface.frameblend[0].lerp = 1;
7401 rsurface.ent_alttextures = false;
7402 rsurface.basepolygonfactor = r_refdef.polygonfactor;
7403 rsurface.basepolygonoffset = r_refdef.polygonoffset;
7404 rsurface.entityskeletaltransform3x4 = NULL;
7405 rsurface.entityskeletaltransform3x4buffer = NULL;
7406 rsurface.entityskeletaltransform3x4offset = 0;
7407 rsurface.entityskeletaltransform3x4size = 0;
7408 rsurface.entityskeletalnumtransforms = 0;
7409 r_refdef.stats[r_stat_batch_entitycustom_count]++;
7410 r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7411 r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7412 r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7415 rsurface.modelvertex3f = (float *)vertex3f;
7416 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7417 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7418 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7420 else if (wantnormals)
7422 rsurface.modelvertex3f = (float *)vertex3f;
7423 rsurface.modelsvector3f = NULL;
7424 rsurface.modeltvector3f = NULL;
7425 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7429 rsurface.modelvertex3f = (float *)vertex3f;
7430 rsurface.modelsvector3f = NULL;
7431 rsurface.modeltvector3f = NULL;
7432 rsurface.modelnormal3f = NULL;
7434 rsurface.modelvertexmesh = NULL;
7435 rsurface.modelvertexmesh_vertexbuffer = NULL;
7436 rsurface.modelvertexmesh_bufferoffset = 0;
7437 rsurface.modelvertex3f_vertexbuffer = 0;
7438 rsurface.modelvertex3f_bufferoffset = 0;
7439 rsurface.modelsvector3f_vertexbuffer = 0;
7440 rsurface.modelsvector3f_bufferoffset = 0;
7441 rsurface.modeltvector3f_vertexbuffer = 0;
7442 rsurface.modeltvector3f_bufferoffset = 0;
7443 rsurface.modelnormal3f_vertexbuffer = 0;
7444 rsurface.modelnormal3f_bufferoffset = 0;
7445 rsurface.modelgeneratedvertex = true;
7446 rsurface.modellightmapcolor4f = (float *)color4f;
7447 rsurface.modellightmapcolor4f_vertexbuffer = 0;
7448 rsurface.modellightmapcolor4f_bufferoffset = 0;
7449 rsurface.modeltexcoordtexture2f = (float *)texcoord2f;
7450 rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7451 rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7452 rsurface.modeltexcoordlightmap2f = NULL;
7453 rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7454 rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7455 rsurface.modelskeletalindex4ub = NULL;
7456 rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7457 rsurface.modelskeletalindex4ub_bufferoffset = 0;
7458 rsurface.modelskeletalweight4ub = NULL;
7459 rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7460 rsurface.modelskeletalweight4ub_bufferoffset = 0;
7461 rsurface.modelelement3i = (int *)element3i;
7462 rsurface.modelelement3i_indexbuffer = NULL;
7463 rsurface.modelelement3i_bufferoffset = 0;
7464 rsurface.modelelement3s = (unsigned short *)element3s;
7465 rsurface.modelelement3s_indexbuffer = NULL;
7466 rsurface.modelelement3s_bufferoffset = 0;
7467 rsurface.modellightmapoffsets = NULL;
7468 rsurface.modelsurfaces = NULL;
7469 rsurface.batchgeneratedvertex = false;
7470 rsurface.batchfirstvertex = 0;
7471 rsurface.batchnumvertices = 0;
7472 rsurface.batchfirsttriangle = 0;
7473 rsurface.batchnumtriangles = 0;
7474 rsurface.batchvertex3f = NULL;
7475 rsurface.batchvertex3f_vertexbuffer = NULL;
7476 rsurface.batchvertex3f_bufferoffset = 0;
7477 rsurface.batchsvector3f = NULL;
7478 rsurface.batchsvector3f_vertexbuffer = NULL;
7479 rsurface.batchsvector3f_bufferoffset = 0;
7480 rsurface.batchtvector3f = NULL;
7481 rsurface.batchtvector3f_vertexbuffer = NULL;
7482 rsurface.batchtvector3f_bufferoffset = 0;
7483 rsurface.batchnormal3f = NULL;
7484 rsurface.batchnormal3f_vertexbuffer = NULL;
7485 rsurface.batchnormal3f_bufferoffset = 0;
7486 rsurface.batchlightmapcolor4f = NULL;
7487 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7488 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7489 rsurface.batchtexcoordtexture2f = NULL;
7490 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7491 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7492 rsurface.batchtexcoordlightmap2f = NULL;
7493 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7494 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7495 rsurface.batchskeletalindex4ub = NULL;
7496 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7497 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7498 rsurface.batchskeletalweight4ub = NULL;
7499 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7500 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7501 rsurface.batchvertexmesh = NULL;
7502 rsurface.batchvertexmesh_vertexbuffer = NULL;
7503 rsurface.batchvertexmesh_bufferoffset = 0;
7504 rsurface.batchelement3i = NULL;
7505 rsurface.batchelement3i_indexbuffer = NULL;
7506 rsurface.batchelement3i_bufferoffset = 0;
7507 rsurface.batchelement3s = NULL;
7508 rsurface.batchelement3s_indexbuffer = NULL;
7509 rsurface.batchelement3s_bufferoffset = 0;
7510 rsurface.forcecurrenttextureupdate = true;
7512 if (rsurface.modelnumvertices && rsurface.modelelement3i)
7514 if ((wantnormals || wanttangents) && !normal3f)
7516 rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7517 Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7519 if (wanttangents && !svector3f)
7521 rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7522 rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7523 Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7528 float RSurf_FogPoint(const float *v)
7530 // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7531 float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7532 float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7533 float FogHeightFade = r_refdef.fogheightfade;
7535 unsigned int fogmasktableindex;
7536 if (r_refdef.fogplaneviewabove)
7537 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7539 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7540 fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7541 return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7544 float RSurf_FogVertex(const float *v)
7546 // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7547 float FogPlaneViewDist = rsurface.fogplaneviewdist;
7548 float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7549 float FogHeightFade = rsurface.fogheightfade;
7551 unsigned int fogmasktableindex;
7552 if (r_refdef.fogplaneviewabove)
7553 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7555 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7556 fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7557 return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7560 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7563 for (i = 0;i < numelements;i++)
7564 outelement3i[i] = inelement3i[i] + adjust;
7567 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7568 extern cvar_t gl_vbo;
7569 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7577 int surfacefirsttriangle;
7578 int surfacenumtriangles;
7579 int surfacefirstvertex;
7580 int surfaceendvertex;
7581 int surfacenumvertices;
7582 int batchnumsurfaces = texturenumsurfaces;
7583 int batchnumvertices;
7584 int batchnumtriangles;
7588 qboolean dynamicvertex;
7591 float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7594 q3shaderinfo_deform_t *deform;
7595 const msurface_t *surface, *firstsurface;
7596 r_vertexmesh_t *vertexmesh;
7597 if (!texturenumsurfaces)
7599 // find vertex range of this surface batch
7601 firstsurface = texturesurfacelist[0];
7602 firsttriangle = firstsurface->num_firsttriangle;
7603 batchnumvertices = 0;
7604 batchnumtriangles = 0;
7605 firstvertex = endvertex = firstsurface->num_firstvertex;
7606 for (i = 0;i < texturenumsurfaces;i++)
7608 surface = texturesurfacelist[i];
7609 if (surface != firstsurface + i)
7611 surfacefirstvertex = surface->num_firstvertex;
7612 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7613 surfacenumvertices = surface->num_vertices;
7614 surfacenumtriangles = surface->num_triangles;
7615 if (firstvertex > surfacefirstvertex)
7616 firstvertex = surfacefirstvertex;
7617 if (endvertex < surfaceendvertex)
7618 endvertex = surfaceendvertex;
7619 batchnumvertices += surfacenumvertices;
7620 batchnumtriangles += surfacenumtriangles;
7623 r_refdef.stats[r_stat_batch_batches]++;
7625 r_refdef.stats[r_stat_batch_withgaps]++;
7626 r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7627 r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7628 r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7630 // we now know the vertex range used, and if there are any gaps in it
7631 rsurface.batchfirstvertex = firstvertex;
7632 rsurface.batchnumvertices = endvertex - firstvertex;
7633 rsurface.batchfirsttriangle = firsttriangle;
7634 rsurface.batchnumtriangles = batchnumtriangles;
7636 // this variable holds flags for which properties have been updated that
7637 // may require regenerating vertexmesh array...
7640 // check if any dynamic vertex processing must occur
7641 dynamicvertex = false;
7643 // a cvar to force the dynamic vertex path to be taken, for debugging
7644 if (r_batch_debugdynamicvertexpath.integer)
7648 r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7649 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7650 r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7651 r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7653 dynamicvertex = true;
7656 // if there is a chance of animated vertex colors, it's a dynamic batch
7657 if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo)
7661 r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7662 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7663 r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7664 r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7666 dynamicvertex = true;
7667 needsupdate |= BATCHNEED_VERTEXMESH_VERTEXCOLOR;
7670 for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7672 switch (deform->deform)
7675 case Q3DEFORM_PROJECTIONSHADOW:
7676 case Q3DEFORM_TEXT0:
7677 case Q3DEFORM_TEXT1:
7678 case Q3DEFORM_TEXT2:
7679 case Q3DEFORM_TEXT3:
7680 case Q3DEFORM_TEXT4:
7681 case Q3DEFORM_TEXT5:
7682 case Q3DEFORM_TEXT6:
7683 case Q3DEFORM_TEXT7:
7686 case Q3DEFORM_AUTOSPRITE:
7689 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7690 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7691 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7692 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7694 dynamicvertex = true;
7695 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7696 needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7698 case Q3DEFORM_AUTOSPRITE2:
7701 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7702 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7703 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7704 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7706 dynamicvertex = true;
7707 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7708 needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7710 case Q3DEFORM_NORMAL:
7713 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7714 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7715 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7716 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7718 dynamicvertex = true;
7719 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7720 needsupdate |= BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7723 if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7724 break; // if wavefunc is a nop, ignore this transform
7727 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7728 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7729 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7730 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7732 dynamicvertex = true;
7733 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7734 needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7736 case Q3DEFORM_BULGE:
7739 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7740 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7741 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7742 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7744 dynamicvertex = true;
7745 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7746 needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7749 if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7750 break; // if wavefunc is a nop, ignore this transform
7753 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7754 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7755 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7756 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7758 dynamicvertex = true;
7759 batchneed |= BATCHNEED_ARRAY_VERTEX;
7760 needsupdate |= BATCHNEED_VERTEXMESH_VERTEX;
7764 if (rsurface.texture->materialshaderpass)
7766 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7769 case Q3TCGEN_TEXTURE:
7771 case Q3TCGEN_LIGHTMAP:
7774 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7775 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7776 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7777 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7779 dynamicvertex = true;
7780 batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7781 needsupdate |= BATCHNEED_VERTEXMESH_LIGHTMAP;
7783 case Q3TCGEN_VECTOR:
7786 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7787 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7788 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7789 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7791 dynamicvertex = true;
7792 batchneed |= BATCHNEED_ARRAY_VERTEX;
7793 needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
7795 case Q3TCGEN_ENVIRONMENT:
7798 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7799 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7800 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7801 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7803 dynamicvertex = true;
7804 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7805 needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
7808 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7812 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7813 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7814 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7815 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7817 dynamicvertex = true;
7818 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7819 needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
7823 if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)))
7827 r_refdef.stats[r_stat_batch_dynamic_batches_because_interleavedarrays] += 1;
7828 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_interleavedarrays] += batchnumsurfaces;
7829 r_refdef.stats[r_stat_batch_dynamic_vertices_because_interleavedarrays] += batchnumvertices;
7830 r_refdef.stats[r_stat_batch_dynamic_triangles_because_interleavedarrays] += batchnumtriangles;
7832 dynamicvertex = true;
7833 needsupdate |= (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP));
7836 // when the model data has no vertex buffer (dynamic mesh), we need to
7838 if (vid.useinterleavedarrays && !rsurface.modelvertexmesh_vertexbuffer)
7839 batchneed |= BATCHNEED_NOGAPS;
7841 // the caller can specify BATCHNEED_NOGAPS to force a batch with
7842 // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7843 // we ensure this by treating the vertex batch as dynamic...
7844 if ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0))
7848 r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7849 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7850 r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7851 r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7853 dynamicvertex = true;
7858 // when copying, we need to consider the regeneration of vertexmesh, any dependencies it may have must be set...
7859 if (batchneed & BATCHNEED_VERTEXMESH_VERTEX) batchneed |= BATCHNEED_ARRAY_VERTEX;
7860 if (batchneed & BATCHNEED_VERTEXMESH_NORMAL) batchneed |= BATCHNEED_ARRAY_NORMAL;
7861 if (batchneed & BATCHNEED_VERTEXMESH_VECTOR) batchneed |= BATCHNEED_ARRAY_VECTOR;
7862 if (batchneed & BATCHNEED_VERTEXMESH_VERTEXCOLOR) batchneed |= BATCHNEED_ARRAY_VERTEXCOLOR;
7863 if (batchneed & BATCHNEED_VERTEXMESH_TEXCOORD) batchneed |= BATCHNEED_ARRAY_TEXCOORD;
7864 if (batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP) batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7865 if (batchneed & BATCHNEED_VERTEXMESH_SKELETAL) batchneed |= BATCHNEED_ARRAY_SKELETAL;
7868 // if needsupdate, we have to do a dynamic vertex batch for sure
7869 if (needsupdate & batchneed)
7873 r_refdef.stats[r_stat_batch_dynamic_batches_because_derived] += 1;
7874 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_derived] += batchnumsurfaces;
7875 r_refdef.stats[r_stat_batch_dynamic_vertices_because_derived] += batchnumvertices;
7876 r_refdef.stats[r_stat_batch_dynamic_triangles_because_derived] += batchnumtriangles;
7878 dynamicvertex = true;
7881 // see if we need to build vertexmesh from arrays
7882 if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)))
7886 r_refdef.stats[r_stat_batch_dynamic_batches_because_interleavedarrays] += 1;
7887 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_interleavedarrays] += batchnumsurfaces;
7888 r_refdef.stats[r_stat_batch_dynamic_vertices_because_interleavedarrays] += batchnumvertices;
7889 r_refdef.stats[r_stat_batch_dynamic_triangles_because_interleavedarrays] += batchnumtriangles;
7891 dynamicvertex = true;
7894 // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7895 if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7896 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7898 rsurface.batchvertex3f = rsurface.modelvertex3f;
7899 rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7900 rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7901 rsurface.batchsvector3f = rsurface.modelsvector3f;
7902 rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7903 rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7904 rsurface.batchtvector3f = rsurface.modeltvector3f;
7905 rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7906 rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7907 rsurface.batchnormal3f = rsurface.modelnormal3f;
7908 rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7909 rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7910 rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7911 rsurface.batchlightmapcolor4f_vertexbuffer = rsurface.modellightmapcolor4f_vertexbuffer;
7912 rsurface.batchlightmapcolor4f_bufferoffset = rsurface.modellightmapcolor4f_bufferoffset;
7913 rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7914 rsurface.batchtexcoordtexture2f_vertexbuffer = rsurface.modeltexcoordtexture2f_vertexbuffer;
7915 rsurface.batchtexcoordtexture2f_bufferoffset = rsurface.modeltexcoordtexture2f_bufferoffset;
7916 rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7917 rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7918 rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7919 rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7920 rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7921 rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7922 rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7923 rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7924 rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7925 rsurface.batchvertexmesh = rsurface.modelvertexmesh;
7926 rsurface.batchvertexmesh_vertexbuffer = rsurface.modelvertexmesh_vertexbuffer;
7927 rsurface.batchvertexmesh_bufferoffset = rsurface.modelvertexmesh_bufferoffset;
7928 rsurface.batchelement3i = rsurface.modelelement3i;
7929 rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7930 rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7931 rsurface.batchelement3s = rsurface.modelelement3s;
7932 rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7933 rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7934 rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7935 rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7936 rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7937 rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7938 rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7940 // if any dynamic vertex processing has to occur in software, we copy the
7941 // entire surface list together before processing to rebase the vertices
7942 // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7944 // if any gaps exist and we do not have a static vertex buffer, we have to
7945 // copy the surface list together to avoid wasting upload bandwidth on the
7946 // vertices in the gaps.
7948 // if gaps exist and we have a static vertex buffer, we can choose whether
7949 // to combine the index buffer ranges into one dynamic index buffer or
7950 // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7952 // in many cases the batch is reduced to one draw call.
7954 rsurface.batchmultidraw = false;
7955 rsurface.batchmultidrawnumsurfaces = 0;
7956 rsurface.batchmultidrawsurfacelist = NULL;
7960 // static vertex data, just set pointers...
7961 rsurface.batchgeneratedvertex = false;
7962 // if there are gaps, we want to build a combined index buffer,
7963 // otherwise use the original static buffer with an appropriate offset
7966 r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7967 r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7968 r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7969 r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7970 if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7972 rsurface.batchmultidraw = true;
7973 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7974 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7977 // build a new triangle elements array for this batch
7978 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7979 rsurface.batchfirsttriangle = 0;
7981 for (i = 0;i < texturenumsurfaces;i++)
7983 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7984 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7985 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7986 numtriangles += surfacenumtriangles;
7988 rsurface.batchelement3i_indexbuffer = NULL;
7989 rsurface.batchelement3i_bufferoffset = 0;
7990 rsurface.batchelement3s = NULL;
7991 rsurface.batchelement3s_indexbuffer = NULL;
7992 rsurface.batchelement3s_bufferoffset = 0;
7993 if (endvertex <= 65536)
7995 // make a 16bit (unsigned short) index array if possible
7996 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7997 for (i = 0;i < numtriangles*3;i++)
7998 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
8000 // upload buffer data for the copytriangles batch
8001 if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo)
8003 if (rsurface.batchelement3s)
8004 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
8005 else if (rsurface.batchelement3i)
8006 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
8011 r_refdef.stats[r_stat_batch_fast_batches] += 1;
8012 r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
8013 r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
8014 r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
8019 // something needs software processing, do it for real...
8020 // we only directly handle separate array data in this case and then
8021 // generate interleaved data if needed...
8022 rsurface.batchgeneratedvertex = true;
8023 r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
8024 r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
8025 r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
8026 r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
8028 // now copy the vertex data into a combined array and make an index array
8029 // (this is what Quake3 does all the time)
8030 // we also apply any skeletal animation here that would have been done in
8031 // the vertex shader, because most of the dynamic vertex animation cases
8032 // need actual vertex positions and normals
8033 //if (dynamicvertex)
8035 rsurface.batchvertexmesh = NULL;
8036 rsurface.batchvertexmesh_vertexbuffer = NULL;
8037 rsurface.batchvertexmesh_bufferoffset = 0;
8038 rsurface.batchvertex3f = NULL;
8039 rsurface.batchvertex3f_vertexbuffer = NULL;
8040 rsurface.batchvertex3f_bufferoffset = 0;
8041 rsurface.batchsvector3f = NULL;
8042 rsurface.batchsvector3f_vertexbuffer = NULL;
8043 rsurface.batchsvector3f_bufferoffset = 0;
8044 rsurface.batchtvector3f = NULL;
8045 rsurface.batchtvector3f_vertexbuffer = NULL;
8046 rsurface.batchtvector3f_bufferoffset = 0;
8047 rsurface.batchnormal3f = NULL;
8048 rsurface.batchnormal3f_vertexbuffer = NULL;
8049 rsurface.batchnormal3f_bufferoffset = 0;
8050 rsurface.batchlightmapcolor4f = NULL;
8051 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8052 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8053 rsurface.batchtexcoordtexture2f = NULL;
8054 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8055 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8056 rsurface.batchtexcoordlightmap2f = NULL;
8057 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
8058 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
8059 rsurface.batchskeletalindex4ub = NULL;
8060 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
8061 rsurface.batchskeletalindex4ub_bufferoffset = 0;
8062 rsurface.batchskeletalweight4ub = NULL;
8063 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
8064 rsurface.batchskeletalweight4ub_bufferoffset = 0;
8065 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
8066 rsurface.batchelement3i_indexbuffer = NULL;
8067 rsurface.batchelement3i_bufferoffset = 0;
8068 rsurface.batchelement3s = NULL;
8069 rsurface.batchelement3s_indexbuffer = NULL;
8070 rsurface.batchelement3s_bufferoffset = 0;
8071 rsurface.batchskeletaltransform3x4buffer = NULL;
8072 rsurface.batchskeletaltransform3x4offset = 0;
8073 rsurface.batchskeletaltransform3x4size = 0;
8074 // we'll only be setting up certain arrays as needed
8075 if (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP))
8076 rsurface.batchvertexmesh = (r_vertexmesh_t *)R_FrameData_Alloc(batchnumvertices * sizeof(r_vertexmesh_t));
8077 if (batchneed & BATCHNEED_ARRAY_VERTEX)
8078 rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8079 if (batchneed & BATCHNEED_ARRAY_NORMAL)
8080 rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8081 if (batchneed & BATCHNEED_ARRAY_VECTOR)
8083 rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8084 rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8086 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
8087 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8088 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
8089 rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8090 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
8091 rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8092 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
8094 rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
8095 rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
8099 for (i = 0;i < texturenumsurfaces;i++)
8101 surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
8102 surfacenumvertices = texturesurfacelist[i]->num_vertices;
8103 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
8104 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
8105 // copy only the data requested
8106 if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)) && rsurface.modelvertexmesh)
8107 memcpy(rsurface.batchvertexmesh + numvertices, rsurface.modelvertexmesh + surfacefirstvertex, surfacenumvertices * sizeof(rsurface.batchvertexmesh[0]));
8108 if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
8110 if (batchneed & BATCHNEED_ARRAY_VERTEX)
8112 if (rsurface.batchvertex3f)
8113 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8115 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8117 if (batchneed & BATCHNEED_ARRAY_NORMAL)
8119 if (rsurface.modelnormal3f)
8120 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8122 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8124 if (batchneed & BATCHNEED_ARRAY_VECTOR)
8126 if (rsurface.modelsvector3f)
8128 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8129 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8133 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8134 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8137 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
8139 if (rsurface.modellightmapcolor4f)
8140 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
8142 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
8144 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
8146 if (rsurface.modeltexcoordtexture2f)
8147 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
8149 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
8151 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
8153 if (rsurface.modeltexcoordlightmap2f)
8154 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
8156 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
8158 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
8160 if (rsurface.modelskeletalindex4ub)
8162 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
8163 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
8167 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
8168 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
8169 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
8170 for (j = 0;j < surfacenumvertices;j++)
8175 RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
8176 numvertices += surfacenumvertices;
8177 numtriangles += surfacenumtriangles;
8180 // generate a 16bit index array as well if possible
8181 // (in general, dynamic batches fit)
8182 if (numvertices <= 65536)
8184 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
8185 for (i = 0;i < numtriangles*3;i++)
8186 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
8189 // since we've copied everything, the batch now starts at 0
8190 rsurface.batchfirstvertex = 0;
8191 rsurface.batchnumvertices = batchnumvertices;
8192 rsurface.batchfirsttriangle = 0;
8193 rsurface.batchnumtriangles = batchnumtriangles;
8196 // apply skeletal animation that would have been done in the vertex shader
8197 if (rsurface.batchskeletaltransform3x4)
8199 const unsigned char *si;
8200 const unsigned char *sw;
8202 const float *b = rsurface.batchskeletaltransform3x4;
8203 float *vp, *vs, *vt, *vn;
8205 float m[3][4], n[3][4];
8206 float tp[3], ts[3], tt[3], tn[3];
8207 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
8208 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
8209 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
8210 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
8211 si = rsurface.batchskeletalindex4ub;
8212 sw = rsurface.batchskeletalweight4ub;
8213 vp = rsurface.batchvertex3f;
8214 vs = rsurface.batchsvector3f;
8215 vt = rsurface.batchtvector3f;
8216 vn = rsurface.batchnormal3f;
8217 memset(m[0], 0, sizeof(m));
8218 memset(n[0], 0, sizeof(n));
8219 for (i = 0;i < batchnumvertices;i++)
8221 t[0] = b + si[0]*12;
8224 // common case - only one matrix
8238 else if (sw[2] + sw[3])
8241 t[1] = b + si[1]*12;
8242 t[2] = b + si[2]*12;
8243 t[3] = b + si[3]*12;
8244 w[0] = sw[0] * (1.0f / 255.0f);
8245 w[1] = sw[1] * (1.0f / 255.0f);
8246 w[2] = sw[2] * (1.0f / 255.0f);
8247 w[3] = sw[3] * (1.0f / 255.0f);
8248 // blend the matrices
8249 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
8250 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
8251 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
8252 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
8253 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
8254 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
8255 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
8256 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
8257 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
8258 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
8259 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
8260 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
8265 t[1] = b + si[1]*12;
8266 w[0] = sw[0] * (1.0f / 255.0f);
8267 w[1] = sw[1] * (1.0f / 255.0f);
8268 // blend the matrices
8269 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
8270 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
8271 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
8272 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
8273 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
8274 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
8275 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
8276 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
8277 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
8278 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
8279 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
8280 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
8284 // modify the vertex
8286 vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
8287 vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
8288 vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
8292 // the normal transformation matrix is a set of cross products...
8293 CrossProduct(m[1], m[2], n[0]);
8294 CrossProduct(m[2], m[0], n[1]);
8295 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8297 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8298 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8299 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8300 VectorNormalize(vn);
8305 vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8306 vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8307 vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8308 VectorNormalize(vs);
8311 vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8312 vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8313 vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8314 VectorNormalize(vt);
8319 rsurface.batchskeletaltransform3x4 = NULL;
8320 rsurface.batchskeletalnumtransforms = 0;
8323 // q1bsp surfaces rendered in vertex color mode have to have colors
8324 // calculated based on lightstyles
8325 if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo)
8327 // generate color arrays for the surfaces in this list
8332 const unsigned char *lm;
8333 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8334 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8335 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8337 for (i = 0;i < texturenumsurfaces;i++)
8339 surface = texturesurfacelist[i];
8340 offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8341 surfacenumvertices = surface->num_vertices;
8342 if (surface->lightmapinfo->samples)
8344 for (j = 0;j < surfacenumvertices;j++)
8346 lm = surface->lightmapinfo->samples + offsets[j];
8347 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8348 VectorScale(lm, scale, c);
8349 if (surface->lightmapinfo->styles[1] != 255)
8351 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8353 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8354 VectorMA(c, scale, lm, c);
8355 if (surface->lightmapinfo->styles[2] != 255)
8358 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8359 VectorMA(c, scale, lm, c);
8360 if (surface->lightmapinfo->styles[3] != 255)
8363 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8364 VectorMA(c, scale, lm, c);
8371 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);
8377 for (j = 0;j < surfacenumvertices;j++)
8379 Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8386 // if vertices are deformed (sprite flares and things in maps, possibly
8387 // water waves, bulges and other deformations), modify the copied vertices
8389 for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8392 switch (deform->deform)
8395 case Q3DEFORM_PROJECTIONSHADOW:
8396 case Q3DEFORM_TEXT0:
8397 case Q3DEFORM_TEXT1:
8398 case Q3DEFORM_TEXT2:
8399 case Q3DEFORM_TEXT3:
8400 case Q3DEFORM_TEXT4:
8401 case Q3DEFORM_TEXT5:
8402 case Q3DEFORM_TEXT6:
8403 case Q3DEFORM_TEXT7:
8406 case Q3DEFORM_AUTOSPRITE:
8407 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8408 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8409 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8410 VectorNormalize(newforward);
8411 VectorNormalize(newright);
8412 VectorNormalize(newup);
8413 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8414 // rsurface.batchvertex3f_vertexbuffer = NULL;
8415 // rsurface.batchvertex3f_bufferoffset = 0;
8416 // rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8417 // rsurface.batchsvector3f_vertexbuffer = NULL;
8418 // rsurface.batchsvector3f_bufferoffset = 0;
8419 // rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8420 // rsurface.batchtvector3f_vertexbuffer = NULL;
8421 // rsurface.batchtvector3f_bufferoffset = 0;
8422 // rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8423 // rsurface.batchnormal3f_vertexbuffer = NULL;
8424 // rsurface.batchnormal3f_bufferoffset = 0;
8425 // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8426 if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8427 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8428 if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8429 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);
8430 // a single autosprite surface can contain multiple sprites...
8431 for (j = 0;j < batchnumvertices - 3;j += 4)
8433 VectorClear(center);
8434 for (i = 0;i < 4;i++)
8435 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8436 VectorScale(center, 0.25f, center);
8437 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8438 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8439 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8440 for (i = 0;i < 4;i++)
8442 VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8443 VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8446 // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8447 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8448 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);
8450 case Q3DEFORM_AUTOSPRITE2:
8451 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8452 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8453 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8454 VectorNormalize(newforward);
8455 VectorNormalize(newright);
8456 VectorNormalize(newup);
8457 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8458 // rsurface.batchvertex3f_vertexbuffer = NULL;
8459 // rsurface.batchvertex3f_bufferoffset = 0;
8461 const float *v1, *v2;
8471 memset(shortest, 0, sizeof(shortest));
8472 // a single autosprite surface can contain multiple sprites...
8473 for (j = 0;j < batchnumvertices - 3;j += 4)
8475 VectorClear(center);
8476 for (i = 0;i < 4;i++)
8477 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8478 VectorScale(center, 0.25f, center);
8479 // find the two shortest edges, then use them to define the
8480 // axis vectors for rotating around the central axis
8481 for (i = 0;i < 6;i++)
8483 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8484 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8485 l = VectorDistance2(v1, v2);
8486 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8488 l += (1.0f / 1024.0f);
8489 if (shortest[0].length2 > l || i == 0)
8491 shortest[1] = shortest[0];
8492 shortest[0].length2 = l;
8493 shortest[0].v1 = v1;
8494 shortest[0].v2 = v2;
8496 else if (shortest[1].length2 > l || i == 1)
8498 shortest[1].length2 = l;
8499 shortest[1].v1 = v1;
8500 shortest[1].v2 = v2;
8503 VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8504 VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8505 // this calculates the right vector from the shortest edge
8506 // and the up vector from the edge midpoints
8507 VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8508 VectorNormalize(right);
8509 VectorSubtract(end, start, up);
8510 VectorNormalize(up);
8511 // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8512 VectorSubtract(rsurface.localvieworigin, center, forward);
8513 //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8514 VectorNegate(forward, forward);
8515 VectorReflect(forward, 0, up, forward);
8516 VectorNormalize(forward);
8517 CrossProduct(up, forward, newright);
8518 VectorNormalize(newright);
8519 // rotate the quad around the up axis vector, this is made
8520 // especially easy by the fact we know the quad is flat,
8521 // so we only have to subtract the center position and
8522 // measure distance along the right vector, and then
8523 // multiply that by the newright vector and add back the
8525 // we also need to subtract the old position to undo the
8526 // displacement from the center, which we do with a
8527 // DotProduct, the subtraction/addition of center is also
8528 // optimized into DotProducts here
8529 l = DotProduct(right, center);
8530 for (i = 0;i < 4;i++)
8532 v1 = rsurface.batchvertex3f + 3*(j+i);
8533 f = DotProduct(right, v1) - l;
8534 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8538 if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8540 // rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8541 // rsurface.batchnormal3f_vertexbuffer = NULL;
8542 // rsurface.batchnormal3f_bufferoffset = 0;
8543 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8545 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8547 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8548 // rsurface.batchsvector3f_vertexbuffer = NULL;
8549 // rsurface.batchsvector3f_bufferoffset = 0;
8550 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8551 // rsurface.batchtvector3f_vertexbuffer = NULL;
8552 // rsurface.batchtvector3f_bufferoffset = 0;
8553 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);
8556 case Q3DEFORM_NORMAL:
8557 // deform the normals to make reflections wavey
8558 rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8559 rsurface.batchnormal3f_vertexbuffer = NULL;
8560 rsurface.batchnormal3f_bufferoffset = 0;
8561 for (j = 0;j < batchnumvertices;j++)
8564 float *normal = rsurface.batchnormal3f + 3*j;
8565 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8566 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f( vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8567 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8568 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8569 VectorNormalize(normal);
8571 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8573 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8574 // rsurface.batchsvector3f_vertexbuffer = NULL;
8575 // rsurface.batchsvector3f_bufferoffset = 0;
8576 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8577 // rsurface.batchtvector3f_vertexbuffer = NULL;
8578 // rsurface.batchtvector3f_bufferoffset = 0;
8579 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);
8583 // deform vertex array to make wavey water and flags and such
8584 waveparms[0] = deform->waveparms[0];
8585 waveparms[1] = deform->waveparms[1];
8586 waveparms[2] = deform->waveparms[2];
8587 waveparms[3] = deform->waveparms[3];
8588 if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8589 break; // if wavefunc is a nop, don't make a dynamic vertex array
8590 // this is how a divisor of vertex influence on deformation
8591 animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8592 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8593 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8594 // rsurface.batchvertex3f_vertexbuffer = NULL;
8595 // rsurface.batchvertex3f_bufferoffset = 0;
8596 // rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8597 // rsurface.batchnormal3f_vertexbuffer = NULL;
8598 // rsurface.batchnormal3f_bufferoffset = 0;
8599 for (j = 0;j < batchnumvertices;j++)
8601 // if the wavefunc depends on time, evaluate it per-vertex
8604 waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8605 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8607 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8609 // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8610 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8611 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8613 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8614 // rsurface.batchsvector3f_vertexbuffer = NULL;
8615 // rsurface.batchsvector3f_bufferoffset = 0;
8616 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8617 // rsurface.batchtvector3f_vertexbuffer = NULL;
8618 // rsurface.batchtvector3f_bufferoffset = 0;
8619 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);
8622 case Q3DEFORM_BULGE:
8623 // deform vertex array to make the surface have moving bulges
8624 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8625 // rsurface.batchvertex3f_vertexbuffer = NULL;
8626 // rsurface.batchvertex3f_bufferoffset = 0;
8627 // rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8628 // rsurface.batchnormal3f_vertexbuffer = NULL;
8629 // rsurface.batchnormal3f_bufferoffset = 0;
8630 for (j = 0;j < batchnumvertices;j++)
8632 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8633 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8635 // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8636 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8637 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8639 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8640 // rsurface.batchsvector3f_vertexbuffer = NULL;
8641 // rsurface.batchsvector3f_bufferoffset = 0;
8642 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8643 // rsurface.batchtvector3f_vertexbuffer = NULL;
8644 // rsurface.batchtvector3f_bufferoffset = 0;
8645 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);
8649 // deform vertex array
8650 if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8651 break; // if wavefunc is a nop, don't make a dynamic vertex array
8652 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8653 VectorScale(deform->parms, scale, waveparms);
8654 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8655 // rsurface.batchvertex3f_vertexbuffer = NULL;
8656 // rsurface.batchvertex3f_bufferoffset = 0;
8657 for (j = 0;j < batchnumvertices;j++)
8658 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8663 if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8665 // generate texcoords based on the chosen texcoord source
8666 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8669 case Q3TCGEN_TEXTURE:
8671 case Q3TCGEN_LIGHTMAP:
8672 // rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8673 // rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8674 // rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8675 if (rsurface.batchtexcoordlightmap2f)
8676 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8678 case Q3TCGEN_VECTOR:
8679 // rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8680 // rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8681 // rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8682 for (j = 0;j < batchnumvertices;j++)
8684 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8685 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8688 case Q3TCGEN_ENVIRONMENT:
8689 // make environment reflections using a spheremap
8690 rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8691 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8692 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8693 for (j = 0;j < batchnumvertices;j++)
8695 // identical to Q3A's method, but executed in worldspace so
8696 // carried models can be shiny too
8698 float viewer[3], d, reflected[3], worldreflected[3];
8700 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8701 // VectorNormalize(viewer);
8703 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8705 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8706 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8707 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8708 // note: this is proportinal to viewer, so we can normalize later
8710 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8711 VectorNormalize(worldreflected);
8713 // note: this sphere map only uses world x and z!
8714 // so positive and negative y will LOOK THE SAME.
8715 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8716 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8720 // the only tcmod that needs software vertex processing is turbulent, so
8721 // check for it here and apply the changes if needed
8722 // and we only support that as the first one
8723 // (handling a mixture of turbulent and other tcmods would be problematic
8724 // without punting it entirely to a software path)
8725 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8727 amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8728 animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8729 // rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8730 // rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8731 // rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8732 for (j = 0;j < batchnumvertices;j++)
8734 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);
8735 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1] ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8740 if (needsupdate & batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP))
8742 // convert the modified arrays to vertex structs
8743 // rsurface.batchvertexmesh = R_FrameData_Alloc(batchnumvertices * sizeof(r_vertexmesh_t));
8744 // rsurface.batchvertexmesh_vertexbuffer = NULL;
8745 // rsurface.batchvertexmesh_bufferoffset = 0;
8746 if (batchneed & BATCHNEED_VERTEXMESH_VERTEX)
8747 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8748 VectorCopy(rsurface.batchvertex3f + 3*j, vertexmesh->vertex3f);
8749 if (batchneed & BATCHNEED_VERTEXMESH_NORMAL)
8750 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8751 VectorCopy(rsurface.batchnormal3f + 3*j, vertexmesh->normal3f);
8752 if (batchneed & BATCHNEED_VERTEXMESH_VECTOR)
8754 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8756 VectorCopy(rsurface.batchsvector3f + 3*j, vertexmesh->svector3f);
8757 VectorCopy(rsurface.batchtvector3f + 3*j, vertexmesh->tvector3f);
8760 if ((batchneed & BATCHNEED_VERTEXMESH_VERTEXCOLOR) && rsurface.batchlightmapcolor4f)
8761 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8762 Vector4Copy(rsurface.batchlightmapcolor4f + 4*j, vertexmesh->color4f);
8763 if (batchneed & BATCHNEED_VERTEXMESH_TEXCOORD)
8764 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8765 Vector2Copy(rsurface.batchtexcoordtexture2f + 2*j, vertexmesh->texcoordtexture2f);
8766 if ((batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP) && rsurface.batchtexcoordlightmap2f)
8767 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8768 Vector2Copy(rsurface.batchtexcoordlightmap2f + 2*j, vertexmesh->texcoordlightmap2f);
8769 if ((batchneed & BATCHNEED_VERTEXMESH_SKELETAL) && rsurface.batchskeletalindex4ub)
8771 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8773 Vector4Copy(rsurface.batchskeletalindex4ub + 4*j, vertexmesh->skeletalindex4ub);
8774 Vector4Copy(rsurface.batchskeletalweight4ub + 4*j, vertexmesh->skeletalweight4ub);
8779 // upload buffer data for the dynamic batch
8780 if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicvertex.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo)
8782 if (rsurface.batchvertexmesh)
8783 rsurface.batchvertexmesh_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(r_vertexmesh_t), rsurface.batchvertexmesh, R_BUFFERDATA_VERTEX, &rsurface.batchvertexmesh_bufferoffset);
8786 if (rsurface.batchvertex3f)
8787 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
8788 if (rsurface.batchsvector3f)
8789 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
8790 if (rsurface.batchtvector3f)
8791 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
8792 if (rsurface.batchnormal3f)
8793 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
8794 if (rsurface.batchlightmapcolor4f)
8795 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
8796 if (rsurface.batchtexcoordtexture2f)
8797 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
8798 if (rsurface.batchtexcoordlightmap2f)
8799 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
8800 if (rsurface.batchskeletalindex4ub)
8801 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
8802 if (rsurface.batchskeletalweight4ub)
8803 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
8805 if (rsurface.batchelement3s)
8806 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
8807 else if (rsurface.batchelement3i)
8808 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
8812 void RSurf_DrawBatch(void)
8814 // sometimes a zero triangle surface (usually a degenerate patch) makes it
8815 // through the pipeline, killing it earlier in the pipeline would have
8816 // per-surface overhead rather than per-batch overhead, so it's best to
8817 // reject it here, before it hits glDraw.
8818 if (rsurface.batchnumtriangles == 0)
8821 // batch debugging code
8822 if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8828 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8829 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8832 for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8834 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8836 if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8837 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);
8844 if (rsurface.batchmultidraw)
8846 // issue multiple draws rather than copying index data
8847 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8848 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8849 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8850 for (i = 0;i < numsurfaces;)
8852 // combine consecutive surfaces as one draw
8853 for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8854 if (surfacelist[j] != surfacelist[k] + 1)
8856 firstvertex = surfacelist[i]->num_firstvertex;
8857 endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8858 firsttriangle = surfacelist[i]->num_firsttriangle;
8859 endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8860 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);
8866 // there is only one consecutive run of index data (may have been combined)
8867 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);
8871 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8873 // pick the closest matching water plane
8874 int planeindex, vertexindex, bestplaneindex = -1;
8878 r_waterstate_waterplane_t *p;
8879 qboolean prepared = false;
8881 for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8883 if(p->camera_entity != rsurface.texture->camera_entity)
8888 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8890 if(rsurface.batchnumvertices == 0)
8893 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8895 Matrix4x4_Transform(&rsurface.matrix, v, vert);
8896 d += fabs(PlaneDiff(vert, &p->plane));
8898 if (bestd > d || bestplaneindex < 0)
8901 bestplaneindex = planeindex;
8904 return bestplaneindex;
8905 // NOTE: this MAY return a totally unrelated water plane; we can ignore
8906 // this situation though, as it might be better to render single larger
8907 // batches with useless stuff (backface culled for example) than to
8908 // render multiple smaller batches
8911 void RSurf_SetupDepthAndCulling(void)
8913 // submodels are biased to avoid z-fighting with world surfaces that they
8914 // may be exactly overlapping (avoids z-fighting artifacts on certain
8915 // doors and things in Quake maps)
8916 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8917 GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8918 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8919 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8922 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8925 // transparent sky would be ridiculous
8926 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8928 R_SetupShader_Generic_NoTexture(false, false);
8929 skyrenderlater = true;
8930 RSurf_SetupDepthAndCulling();
8933 // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8934 if (r_sky_scissor.integer)
8936 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8937 for (i = 0; i < texturenumsurfaces; i++)
8939 const msurface_t *surf = texturesurfacelist[i];
8942 float mins[3], maxs[3];
8944 for (j = 0, v = rsurface.batchvertex3f + 3 * surf->num_firstvertex; j < surf->num_vertices; j++, v += 3)
8946 Matrix4x4_Transform(&rsurface.matrix, v, p);
8949 if (mins[0] > p[0]) mins[0] = p[0];
8950 if (mins[1] > p[1]) mins[1] = p[1];
8951 if (mins[2] > p[2]) mins[2] = p[2];
8952 if (maxs[0] < p[0]) maxs[0] = p[0];
8953 if (maxs[1] < p[1]) maxs[1] = p[1];
8954 if (maxs[2] < p[2]) maxs[2] = p[2];
8958 VectorCopy(p, mins);
8959 VectorCopy(p, maxs);
8962 if (!R_ScissorForBBox(mins, maxs, scissor))
8966 if (skyscissor[0] > scissor[0])
8968 skyscissor[2] += skyscissor[0] - scissor[0];
8969 skyscissor[0] = scissor[0];
8971 if (skyscissor[1] > scissor[1])
8973 skyscissor[3] += skyscissor[1] - scissor[1];
8974 skyscissor[1] = scissor[1];
8976 if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8977 skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8978 if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8979 skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8982 Vector4Copy(scissor, skyscissor);
8987 // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8988 // skymasking on them, and Quake3 never did sky masking (unlike
8989 // software Quake and software Quake2), so disable the sky masking
8990 // in Quake3 maps as it causes problems with q3map2 sky tricks,
8991 // and skymasking also looks very bad when noclipping outside the
8992 // level, so don't use it then either.
8993 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)
8995 R_Mesh_ResetTextureState();
8996 if (skyrendermasked)
8998 R_SetupShader_DepthOrShadow(false, false, false);
8999 // depth-only (masking)
9000 GL_ColorMask(0, 0, 0, 0);
9001 // just to make sure that braindead drivers don't draw
9002 // anything despite that colormask...
9003 GL_BlendFunc(GL_ZERO, GL_ONE);
9004 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9005 R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9009 R_SetupShader_Generic_NoTexture(false, false);
9011 GL_BlendFunc(GL_ONE, GL_ZERO);
9012 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9013 GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
9014 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9017 if (skyrendermasked)
9018 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
9020 R_Mesh_ResetTextureState();
9021 GL_Color(1, 1, 1, 1);
9024 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
9025 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
9026 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
9028 if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
9032 // render screenspace normalmap to texture
9034 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false);
9039 // bind lightmap texture
9041 // water/refraction/reflection/camera surfaces have to be handled specially
9042 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
9044 int start, end, startplaneindex;
9045 for (start = 0;start < texturenumsurfaces;start = end)
9047 startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
9048 if(startplaneindex < 0)
9050 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
9051 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
9055 for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
9057 // now that we have a batch using the same planeindex, render it
9058 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
9060 // render water or distortion background
9062 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
9064 // blend surface on top
9065 GL_DepthMask(false);
9066 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false);
9069 else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
9071 // render surface with reflection texture as input
9072 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
9073 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
9080 // render surface batch normally
9081 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
9082 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0);
9086 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
9090 r_vertexgeneric_t *batchvertex;
9092 texture_t *t = rsurface.texture;
9094 // R_Mesh_ResetTextureState();
9095 R_SetupShader_Generic_NoTexture(false, false);
9097 if(t && t->currentskinframe)
9099 memcpy(c, t->currentskinframe->avgcolor, sizeof(c));
9100 c[3] *= t->currentalpha;
9110 if (t->pantstexture || t->shirttexture)
9112 c[0] = 0.5 * (t->render_colormap_pants[0] * 0.3 + t->render_colormap_shirt[0] * 0.7);
9113 c[1] = 0.5 * (t->render_colormap_pants[1] * 0.3 + t->render_colormap_shirt[1] * 0.7);
9114 c[2] = 0.5 * (t->render_colormap_pants[2] * 0.3 + t->render_colormap_shirt[2] * 0.7);
9117 // brighten it up (as texture value 127 means "unlit")
9118 c[0] *= 2 * r_refdef.view.colorscale;
9119 c[1] *= 2 * r_refdef.view.colorscale;
9120 c[2] *= 2 * r_refdef.view.colorscale;
9122 if(t->currentmaterialflags & MATERIALFLAG_WATERALPHA)
9123 c[3] *= r_wateralpha.value;
9125 if(t->currentmaterialflags & MATERIALFLAG_ALPHA && c[3] != 1)
9127 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9128 GL_DepthMask(false);
9130 else if(t->currentmaterialflags & MATERIALFLAG_ADD)
9132 GL_BlendFunc(GL_ONE, GL_ONE);
9133 GL_DepthMask(false);
9135 else if(t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
9137 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // can't do alpha test without texture, so let's blend instead
9138 GL_DepthMask(false);
9140 else if(t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
9142 GL_BlendFunc(t->customblendfunc[0], t->customblendfunc[1]);
9143 GL_DepthMask(false);
9147 GL_BlendFunc(GL_ONE, GL_ZERO);
9148 GL_DepthMask(writedepth);
9151 if (!r_refdef.view.showdebug)
9153 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9154 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices);
9155 for (j = 0, vi = 0;j < rsurface.batchnumvertices;j++, vi++)
9157 VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
9158 Vector4Set(batchvertex[vi].color4f, 0, 0, 0, 1);
9160 R_Mesh_PrepareVertices_Generic_Unlock();
9163 else if (r_showsurfaces.integer == 4)
9165 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9166 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices);
9167 for (j = 0, vi = 0;j < rsurface.batchnumvertices;j++, vi++)
9169 float d = (vi << 3) * (1.0f / 256.0f);
9170 VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
9171 Vector4Set(batchvertex[vi].color4f, d, d, d, 1);
9173 R_Mesh_PrepareVertices_Generic_Unlock();
9176 else if (r_showsurfaces.integer == 2)
9179 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9180 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(3*rsurface.batchnumtriangles);
9181 for (j = 0, e = rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle;j < rsurface.batchnumtriangles;j++, e += 3)
9183 float d = ((j + rsurface.batchfirsttriangle) << 3) * (1.0f / 256.0f);
9184 VectorCopy(rsurface.batchvertex3f + 3*e[0], batchvertex[j*3+0].vertex3f);
9185 VectorCopy(rsurface.batchvertex3f + 3*e[1], batchvertex[j*3+1].vertex3f);
9186 VectorCopy(rsurface.batchvertex3f + 3*e[2], batchvertex[j*3+2].vertex3f);
9187 Vector4Set(batchvertex[j*3+0].color4f, d, d, d, 1);
9188 Vector4Set(batchvertex[j*3+1].color4f, d, d, d, 1);
9189 Vector4Set(batchvertex[j*3+2].color4f, d, d, d, 1);
9191 R_Mesh_PrepareVertices_Generic_Unlock();
9192 R_Mesh_Draw(0, rsurface.batchnumtriangles*3, 0, rsurface.batchnumtriangles, NULL, NULL, 0, NULL, NULL, 0);
9196 int texturesurfaceindex;
9198 const msurface_t *surface;
9199 float surfacecolor4f[4];
9200 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9201 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchfirstvertex + rsurface.batchnumvertices);
9203 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
9205 surface = texturesurfacelist[texturesurfaceindex];
9206 k = (int)(((size_t)surface) / sizeof(msurface_t));
9207 Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
9208 for (j = 0;j < surface->num_vertices;j++)
9210 VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
9211 Vector4Copy(surfacecolor4f, batchvertex[vi].color4f);
9215 R_Mesh_PrepareVertices_Generic_Unlock();
9220 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
9223 RSurf_SetupDepthAndCulling();
9224 if (r_showsurfaces.integer)
9226 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
9229 switch (vid.renderpath)
9231 case RENDERPATH_GL20:
9232 case RENDERPATH_GLES2:
9233 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
9239 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9242 int texturenumsurfaces, endsurface;
9244 const msurface_t *surface;
9245 const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
9247 RSurf_ActiveModelEntity(ent, true, true, false);
9249 if (r_transparentdepthmasking.integer)
9251 qboolean setup = false;
9252 for (i = 0;i < numsurfaces;i = j)
9255 surface = rsurface.modelsurfaces + surfacelist[i];
9256 texture = surface->texture;
9257 rsurface.texture = R_GetCurrentTexture(texture);
9258 rsurface.lightmaptexture = NULL;
9259 rsurface.deluxemaptexture = NULL;
9260 rsurface.uselightmaptexture = false;
9261 // scan ahead until we find a different texture
9262 endsurface = min(i + 1024, numsurfaces);
9263 texturenumsurfaces = 0;
9264 texturesurfacelist[texturenumsurfaces++] = surface;
9265 for (;j < endsurface;j++)
9267 surface = rsurface.modelsurfaces + surfacelist[j];
9268 if (texture != surface->texture)
9270 texturesurfacelist[texturenumsurfaces++] = surface;
9272 if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
9274 // render the range of surfaces as depth
9278 GL_ColorMask(0,0,0,0);
9281 GL_BlendFunc(GL_ONE, GL_ZERO);
9283 // R_Mesh_ResetTextureState();
9285 RSurf_SetupDepthAndCulling();
9286 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9287 R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9288 R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9292 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
9295 for (i = 0;i < numsurfaces;i = j)
9298 surface = rsurface.modelsurfaces + surfacelist[i];
9299 texture = surface->texture;
9300 rsurface.texture = R_GetCurrentTexture(texture);
9301 // scan ahead until we find a different texture
9302 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
9303 texturenumsurfaces = 0;
9304 texturesurfacelist[texturenumsurfaces++] = surface;
9305 if(FAKELIGHT_ENABLED)
9307 rsurface.lightmaptexture = NULL;
9308 rsurface.deluxemaptexture = NULL;
9309 rsurface.uselightmaptexture = false;
9310 for (;j < endsurface;j++)
9312 surface = rsurface.modelsurfaces + surfacelist[j];
9313 if (texture != surface->texture)
9315 texturesurfacelist[texturenumsurfaces++] = surface;
9320 rsurface.lightmaptexture = surface->lightmaptexture;
9321 rsurface.deluxemaptexture = surface->deluxemaptexture;
9322 rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
9323 for (;j < endsurface;j++)
9325 surface = rsurface.modelsurfaces + surfacelist[j];
9326 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
9328 texturesurfacelist[texturenumsurfaces++] = surface;
9331 // render the range of surfaces
9332 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false);
9334 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
9337 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9339 // transparent surfaces get pushed off into the transparent queue
9340 int surfacelistindex;
9341 const msurface_t *surface;
9342 vec3_t tempcenter, center;
9343 for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
9345 surface = texturesurfacelist[surfacelistindex];
9346 if (r_transparent_sortsurfacesbynearest.integer)
9348 tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
9349 tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
9350 tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
9354 tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
9355 tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
9356 tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
9358 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
9359 if (rsurface.entity->transparent_offset) // transparent offset
9361 center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
9362 center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
9363 center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
9365 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);
9369 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9371 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
9373 if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
9375 RSurf_SetupDepthAndCulling();
9376 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9377 R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9378 R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9382 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass)
9386 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
9389 if (!rsurface.texture->currentnumlayers)
9391 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
9392 R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9394 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
9396 else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
9397 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
9398 else if (!rsurface.texture->currentnumlayers)
9400 else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
9402 // in the deferred case, transparent surfaces were queued during prepass
9403 if (!r_shadow_usingdeferredprepass)
9404 R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9408 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
9409 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass);
9414 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass)
9418 R_FrameData_SetMark();
9419 // break the surface list down into batches by texture and use of lightmapping
9420 for (i = 0;i < numsurfaces;i = j)
9423 // texture is the base texture pointer, rsurface.texture is the
9424 // current frame/skin the texture is directing us to use (for example
9425 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
9426 // use skin 1 instead)
9427 texture = surfacelist[i]->texture;
9428 rsurface.texture = R_GetCurrentTexture(texture);
9429 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
9431 // if this texture is not the kind we want, skip ahead to the next one
9432 for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9436 if(FAKELIGHT_ENABLED || depthonly || prepass)
9438 rsurface.lightmaptexture = NULL;
9439 rsurface.deluxemaptexture = NULL;
9440 rsurface.uselightmaptexture = false;
9441 // simply scan ahead until we find a different texture or lightmap state
9442 for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9447 rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
9448 rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
9449 rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
9450 // simply scan ahead until we find a different texture or lightmap state
9451 for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
9454 // render the range of surfaces
9455 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass);
9457 R_FrameData_ReturnToMark();
9460 float locboxvertex3f[6*4*3] =
9462 1,0,1, 1,0,0, 1,1,0, 1,1,1,
9463 0,1,1, 0,1,0, 0,0,0, 0,0,1,
9464 1,1,1, 1,1,0, 0,1,0, 0,1,1,
9465 0,0,1, 0,0,0, 1,0,0, 1,0,1,
9466 0,0,1, 1,0,1, 1,1,1, 0,1,1,
9467 1,0,0, 0,0,0, 0,1,0, 1,1,0
9470 unsigned short locboxelements[6*2*3] =
9480 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9483 cl_locnode_t *loc = (cl_locnode_t *)ent;
9485 float vertex3f[6*4*3];
9487 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9488 GL_DepthMask(false);
9489 GL_DepthRange(0, 1);
9490 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9492 GL_CullFace(GL_NONE);
9493 R_EntityMatrix(&identitymatrix);
9495 // R_Mesh_ResetTextureState();
9498 GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9499 ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9500 ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9501 surfacelist[0] < 0 ? 0.5f : 0.125f);
9503 if (VectorCompare(loc->mins, loc->maxs))
9505 VectorSet(size, 2, 2, 2);
9506 VectorMA(loc->mins, -0.5f, size, mins);
9510 VectorCopy(loc->mins, mins);
9511 VectorSubtract(loc->maxs, loc->mins, size);
9514 for (i = 0;i < 6*4*3;)
9515 for (j = 0;j < 3;j++, i++)
9516 vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9518 R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9519 R_SetupShader_Generic_NoTexture(false, false);
9520 R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9523 void R_DrawLocs(void)
9526 cl_locnode_t *loc, *nearestloc;
9528 nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9529 for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9531 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9532 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9536 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9538 if (decalsystem->decals)
9539 Mem_Free(decalsystem->decals);
9540 memset(decalsystem, 0, sizeof(*decalsystem));
9543 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)
9549 // expand or initialize the system
9550 if (decalsystem->maxdecals <= decalsystem->numdecals)
9552 decalsystem_t old = *decalsystem;
9553 qboolean useshortelements;
9554 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9555 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9556 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)));
9557 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9558 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9559 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9560 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9561 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9562 if (decalsystem->numdecals)
9563 memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9565 Mem_Free(old.decals);
9566 for (i = 0;i < decalsystem->maxdecals*3;i++)
9567 decalsystem->element3i[i] = i;
9568 if (useshortelements)
9569 for (i = 0;i < decalsystem->maxdecals*3;i++)
9570 decalsystem->element3s[i] = i;
9573 // grab a decal and search for another free slot for the next one
9574 decals = decalsystem->decals;
9575 decal = decalsystem->decals + (i = decalsystem->freedecal++);
9576 for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9578 decalsystem->freedecal = i;
9579 if (decalsystem->numdecals <= i)
9580 decalsystem->numdecals = i + 1;
9582 // initialize the decal
9584 decal->triangleindex = triangleindex;
9585 decal->surfaceindex = surfaceindex;
9586 decal->decalsequence = decalsequence;
9587 decal->color4f[0][0] = c0[0];
9588 decal->color4f[0][1] = c0[1];
9589 decal->color4f[0][2] = c0[2];
9590 decal->color4f[0][3] = 1;
9591 decal->color4f[1][0] = c1[0];
9592 decal->color4f[1][1] = c1[1];
9593 decal->color4f[1][2] = c1[2];
9594 decal->color4f[1][3] = 1;
9595 decal->color4f[2][0] = c2[0];
9596 decal->color4f[2][1] = c2[1];
9597 decal->color4f[2][2] = c2[2];
9598 decal->color4f[2][3] = 1;
9599 decal->vertex3f[0][0] = v0[0];
9600 decal->vertex3f[0][1] = v0[1];
9601 decal->vertex3f[0][2] = v0[2];
9602 decal->vertex3f[1][0] = v1[0];
9603 decal->vertex3f[1][1] = v1[1];
9604 decal->vertex3f[1][2] = v1[2];
9605 decal->vertex3f[2][0] = v2[0];
9606 decal->vertex3f[2][1] = v2[1];
9607 decal->vertex3f[2][2] = v2[2];
9608 decal->texcoord2f[0][0] = t0[0];
9609 decal->texcoord2f[0][1] = t0[1];
9610 decal->texcoord2f[1][0] = t1[0];
9611 decal->texcoord2f[1][1] = t1[1];
9612 decal->texcoord2f[2][0] = t2[0];
9613 decal->texcoord2f[2][1] = t2[1];
9614 TriangleNormal(v0, v1, v2, decal->plane);
9615 VectorNormalize(decal->plane);
9616 decal->plane[3] = DotProduct(v0, decal->plane);
9619 extern cvar_t cl_decals_bias;
9620 extern cvar_t cl_decals_models;
9621 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9622 // baseparms, parms, temps
9623 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)
9628 const float *vertex3f;
9629 const float *normal3f;
9631 float points[2][9][3];
9638 e = rsurface.modelelement3i + 3*triangleindex;
9640 vertex3f = rsurface.modelvertex3f;
9641 normal3f = rsurface.modelnormal3f;
9645 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9647 index = 3*e[cornerindex];
9648 VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9653 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9655 index = 3*e[cornerindex];
9656 VectorCopy(vertex3f + index, v[cornerindex]);
9661 //TriangleNormal(v[0], v[1], v[2], normal);
9662 //if (DotProduct(normal, localnormal) < 0.0f)
9664 // clip by each of the box planes formed from the projection matrix
9665 // if anything survives, we emit the decal
9666 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]);
9669 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]);
9672 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]);
9675 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]);
9678 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]);
9681 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]);
9684 // some part of the triangle survived, so we have to accept it...
9687 // dynamic always uses the original triangle
9689 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9691 index = 3*e[cornerindex];
9692 VectorCopy(vertex3f + index, v[cornerindex]);
9695 for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9697 // convert vertex positions to texcoords
9698 Matrix4x4_Transform(projection, v[cornerindex], temp);
9699 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9700 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9701 // calculate distance fade from the projection origin
9702 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9703 f = bound(0.0f, f, 1.0f);
9704 c[cornerindex][0] = r * f;
9705 c[cornerindex][1] = g * f;
9706 c[cornerindex][2] = b * f;
9707 c[cornerindex][3] = 1.0f;
9708 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9711 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);
9713 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9714 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);
9716 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)
9718 matrix4x4_t projection;
9719 decalsystem_t *decalsystem;
9722 const msurface_t *surface;
9723 const msurface_t *surfaces;
9724 const int *surfacelist;
9725 const texture_t *texture;
9728 int surfacelistindex;
9731 float localorigin[3];
9732 float localnormal[3];
9740 int bih_triangles_count;
9741 int bih_triangles[256];
9742 int bih_surfaces[256];
9744 decalsystem = &ent->decalsystem;
9746 if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9748 R_DecalSystem_Reset(&ent->decalsystem);
9752 if (!model->brush.data_leafs && !cl_decals_models.integer)
9754 if (decalsystem->model)
9755 R_DecalSystem_Reset(decalsystem);
9759 if (decalsystem->model != model)
9760 R_DecalSystem_Reset(decalsystem);
9761 decalsystem->model = model;
9763 RSurf_ActiveModelEntity(ent, true, false, false);
9765 Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9766 Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9767 VectorNormalize(localnormal);
9768 localsize = worldsize*rsurface.inversematrixscale;
9769 localmins[0] = localorigin[0] - localsize;
9770 localmins[1] = localorigin[1] - localsize;
9771 localmins[2] = localorigin[2] - localsize;
9772 localmaxs[0] = localorigin[0] + localsize;
9773 localmaxs[1] = localorigin[1] + localsize;
9774 localmaxs[2] = localorigin[2] + localsize;
9776 //VectorCopy(localnormal, planes[4]);
9777 //VectorVectors(planes[4], planes[2], planes[0]);
9778 AnglesFromVectors(angles, localnormal, NULL, false);
9779 AngleVectors(angles, planes[0], planes[2], planes[4]);
9780 VectorNegate(planes[0], planes[1]);
9781 VectorNegate(planes[2], planes[3]);
9782 VectorNegate(planes[4], planes[5]);
9783 planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9784 planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9785 planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9786 planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9787 planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9788 planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9793 matrix4x4_t forwardprojection;
9794 Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9795 Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9800 float projectionvector[4][3];
9801 VectorScale(planes[0], ilocalsize, projectionvector[0]);
9802 VectorScale(planes[2], ilocalsize, projectionvector[1]);
9803 VectorScale(planes[4], ilocalsize, projectionvector[2]);
9804 projectionvector[0][0] = planes[0][0] * ilocalsize;
9805 projectionvector[0][1] = planes[1][0] * ilocalsize;
9806 projectionvector[0][2] = planes[2][0] * ilocalsize;
9807 projectionvector[1][0] = planes[0][1] * ilocalsize;
9808 projectionvector[1][1] = planes[1][1] * ilocalsize;
9809 projectionvector[1][2] = planes[2][1] * ilocalsize;
9810 projectionvector[2][0] = planes[0][2] * ilocalsize;
9811 projectionvector[2][1] = planes[1][2] * ilocalsize;
9812 projectionvector[2][2] = planes[2][2] * ilocalsize;
9813 projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9814 projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9815 projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9816 Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9820 dynamic = model->surfmesh.isanimated;
9821 numsurfacelist = model->nummodelsurfaces;
9822 surfacelist = model->sortedmodelsurfaces;
9823 surfaces = model->data_surfaces;
9826 bih_triangles_count = -1;
9829 if(model->render_bih.numleafs)
9830 bih = &model->render_bih;
9831 else if(model->collision_bih.numleafs)
9832 bih = &model->collision_bih;
9835 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9836 if(bih_triangles_count == 0)
9838 if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9840 if(bih_triangles_count > 0)
9842 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9844 surfaceindex = bih_surfaces[triangleindex];
9845 surface = surfaces + surfaceindex;
9846 texture = surface->texture;
9847 if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9849 if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9851 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9856 for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
9858 surfaceindex = surfacelist[surfacelistindex];
9859 surface = surfaces + surfaceindex;
9860 // check cull box first because it rejects more than any other check
9861 if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9863 // skip transparent surfaces
9864 texture = surface->texture;
9865 if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9867 if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9869 numtriangles = surface->num_triangles;
9870 for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9871 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9876 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9877 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)
9879 int renderentityindex;
9882 entity_render_t *ent;
9884 if (!cl_decals_newsystem.integer)
9887 worldmins[0] = worldorigin[0] - worldsize;
9888 worldmins[1] = worldorigin[1] - worldsize;
9889 worldmins[2] = worldorigin[2] - worldsize;
9890 worldmaxs[0] = worldorigin[0] + worldsize;
9891 worldmaxs[1] = worldorigin[1] + worldsize;
9892 worldmaxs[2] = worldorigin[2] + worldsize;
9894 R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9896 for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9898 ent = r_refdef.scene.entities[renderentityindex];
9899 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9902 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9906 typedef struct r_decalsystem_splatqueue_s
9913 unsigned int decalsequence;
9915 r_decalsystem_splatqueue_t;
9917 int r_decalsystem_numqueued = 0;
9918 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9920 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)
9922 r_decalsystem_splatqueue_t *queue;
9924 if (!cl_decals_newsystem.integer || r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9927 queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9928 VectorCopy(worldorigin, queue->worldorigin);
9929 VectorCopy(worldnormal, queue->worldnormal);
9930 Vector4Set(queue->color, r, g, b, a);
9931 Vector4Set(queue->tcrange, s1, t1, s2, t2);
9932 queue->worldsize = worldsize;
9933 queue->decalsequence = cl.decalsequence++;
9936 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9939 r_decalsystem_splatqueue_t *queue;
9941 for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9942 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);
9943 r_decalsystem_numqueued = 0;
9946 extern cvar_t cl_decals_max;
9947 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9950 decalsystem_t *decalsystem = &ent->decalsystem;
9952 unsigned int killsequence;
9957 if (!decalsystem->numdecals)
9960 if (r_showsurfaces.integer)
9963 if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9965 R_DecalSystem_Reset(decalsystem);
9969 killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9970 lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9972 if (decalsystem->lastupdatetime)
9973 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9976 decalsystem->lastupdatetime = r_refdef.scene.time;
9977 numdecals = decalsystem->numdecals;
9979 for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9981 if (decal->color4f[0][3])
9983 decal->lived += frametime;
9984 if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9986 memset(decal, 0, sizeof(*decal));
9987 if (decalsystem->freedecal > i)
9988 decalsystem->freedecal = i;
9992 decal = decalsystem->decals;
9993 while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9996 // collapse the array by shuffling the tail decals into the gaps
9999 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
10000 decalsystem->freedecal++;
10001 if (decalsystem->freedecal == numdecals)
10003 decal[decalsystem->freedecal] = decal[--numdecals];
10006 decalsystem->numdecals = numdecals;
10008 if (numdecals <= 0)
10010 // if there are no decals left, reset decalsystem
10011 R_DecalSystem_Reset(decalsystem);
10015 extern skinframe_t *decalskinframe;
10016 static void R_DrawModelDecals_Entity(entity_render_t *ent)
10019 decalsystem_t *decalsystem = &ent->decalsystem;
10028 const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
10031 numdecals = decalsystem->numdecals;
10035 if (r_showsurfaces.integer)
10038 if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
10040 R_DecalSystem_Reset(decalsystem);
10044 // if the model is static it doesn't matter what value we give for
10045 // wantnormals and wanttangents, so this logic uses only rules applicable
10046 // to a model, knowing that they are meaningless otherwise
10047 RSurf_ActiveModelEntity(ent, false, false, false);
10049 decalsystem->lastupdatetime = r_refdef.scene.time;
10051 faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
10053 // update vertex positions for animated models
10054 v3f = decalsystem->vertex3f;
10055 c4f = decalsystem->color4f;
10056 t2f = decalsystem->texcoord2f;
10057 for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
10059 if (!decal->color4f[0][3])
10062 if (surfacevisible && !surfacevisible[decal->surfaceindex])
10066 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
10069 // update color values for fading decals
10070 if (decal->lived >= cl_decals_time.value)
10071 alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
10075 c4f[ 0] = decal->color4f[0][0] * alpha;
10076 c4f[ 1] = decal->color4f[0][1] * alpha;
10077 c4f[ 2] = decal->color4f[0][2] * alpha;
10079 c4f[ 4] = decal->color4f[1][0] * alpha;
10080 c4f[ 5] = decal->color4f[1][1] * alpha;
10081 c4f[ 6] = decal->color4f[1][2] * alpha;
10083 c4f[ 8] = decal->color4f[2][0] * alpha;
10084 c4f[ 9] = decal->color4f[2][1] * alpha;
10085 c4f[10] = decal->color4f[2][2] * alpha;
10088 t2f[0] = decal->texcoord2f[0][0];
10089 t2f[1] = decal->texcoord2f[0][1];
10090 t2f[2] = decal->texcoord2f[1][0];
10091 t2f[3] = decal->texcoord2f[1][1];
10092 t2f[4] = decal->texcoord2f[2][0];
10093 t2f[5] = decal->texcoord2f[2][1];
10095 // update vertex positions for animated models
10096 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
10098 e = rsurface.modelelement3i + 3*decal->triangleindex;
10099 VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
10100 VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
10101 VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
10105 VectorCopy(decal->vertex3f[0], v3f);
10106 VectorCopy(decal->vertex3f[1], v3f + 3);
10107 VectorCopy(decal->vertex3f[2], v3f + 6);
10110 if (r_refdef.fogenabled)
10112 alpha = RSurf_FogVertex(v3f);
10113 VectorScale(c4f, alpha, c4f);
10114 alpha = RSurf_FogVertex(v3f + 3);
10115 VectorScale(c4f + 4, alpha, c4f + 4);
10116 alpha = RSurf_FogVertex(v3f + 6);
10117 VectorScale(c4f + 8, alpha, c4f + 8);
10128 r_refdef.stats[r_stat_drawndecals] += numtris;
10130 // now render the decals all at once
10131 // (this assumes they all use one particle font texture!)
10132 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);
10133 // R_Mesh_ResetTextureState();
10134 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
10135 GL_DepthMask(false);
10136 GL_DepthRange(0, 1);
10137 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
10138 GL_DepthTest(true);
10139 GL_CullFace(GL_NONE);
10140 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
10141 R_SetupShader_Generic(decalskinframe->base, NULL, GL_MODULATE, 1, false, false, false);
10142 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
10146 static void R_DrawModelDecals(void)
10150 // fade faster when there are too many decals
10151 numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
10152 for (i = 0;i < r_refdef.scene.numentities;i++)
10153 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
10155 R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
10156 for (i = 0;i < r_refdef.scene.numentities;i++)
10157 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
10158 R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
10160 R_DecalSystem_ApplySplatEntitiesQueue();
10162 numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
10163 for (i = 0;i < r_refdef.scene.numentities;i++)
10164 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
10166 r_refdef.stats[r_stat_totaldecals] += numdecals;
10168 if (r_showsurfaces.integer)
10171 R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
10173 for (i = 0;i < r_refdef.scene.numentities;i++)
10175 if (!r_refdef.viewcache.entityvisible[i])
10177 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
10178 R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
10182 extern cvar_t mod_collision_bih;
10183 static void R_DrawDebugModel(void)
10185 entity_render_t *ent = rsurface.entity;
10186 int i, j, flagsmask;
10187 const msurface_t *surface;
10188 dp_model_t *model = ent->model;
10190 if (!sv.active && !cls.demoplayback && ent != r_refdef.scene.worldentity)
10193 if (r_showoverdraw.value > 0)
10195 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
10196 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
10197 R_SetupShader_Generic_NoTexture(false, false);
10198 GL_DepthTest(false);
10199 GL_DepthMask(false);
10200 GL_DepthRange(0, 1);
10201 GL_BlendFunc(GL_ONE, GL_ONE);
10202 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10204 if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10206 rsurface.texture = R_GetCurrentTexture(surface->texture);
10207 if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10209 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
10210 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
10211 if (!rsurface.texture->currentlayers->depthmask)
10212 GL_Color(c, 0, 0, 1.0f);
10213 else if (ent == r_refdef.scene.worldentity)
10214 GL_Color(c, c, c, 1.0f);
10216 GL_Color(0, c, 0, 1.0f);
10217 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
10221 rsurface.texture = NULL;
10224 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
10226 // R_Mesh_ResetTextureState();
10227 R_SetupShader_Generic_NoTexture(false, false);
10228 GL_DepthRange(0, 1);
10229 GL_DepthTest(!r_showdisabledepthtest.integer);
10230 GL_DepthMask(false);
10231 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10233 if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
10237 qboolean cullbox = false;
10238 const q3mbrush_t *brush;
10239 const bih_t *bih = &model->collision_bih;
10240 const bih_leaf_t *bihleaf;
10241 float vertex3f[3][3];
10242 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
10243 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
10245 if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
10247 switch (bihleaf->type)
10250 brush = model->brush.data_brushes + bihleaf->itemindex;
10251 if (brush->colbrushf && brush->colbrushf->numtriangles)
10253 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);
10254 R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
10255 R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
10258 case BIH_COLLISIONTRIANGLE:
10259 triangleindex = bihleaf->itemindex;
10260 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
10261 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
10262 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
10263 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);
10264 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
10265 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
10267 case BIH_RENDERTRIANGLE:
10268 triangleindex = bihleaf->itemindex;
10269 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
10270 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
10271 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
10272 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);
10273 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
10274 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
10280 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
10283 if (r_showtris.value > 0 && qglPolygonMode)
10285 if (r_showdisabledepthtest.integer)
10287 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10288 GL_DepthMask(false);
10292 GL_BlendFunc(GL_ONE, GL_ZERO);
10293 GL_DepthMask(true);
10295 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
10296 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10298 if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10300 rsurface.texture = R_GetCurrentTexture(surface->texture);
10301 if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10303 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
10304 if (!rsurface.texture->currentlayers->depthmask)
10305 GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
10306 else if (ent == r_refdef.scene.worldentity)
10307 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
10309 GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
10310 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
10314 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
10315 rsurface.texture = NULL;
10319 // FIXME! implement r_shownormals with just triangles
10320 if (r_shownormals.value != 0 && qglBegin)
10324 if (r_showdisabledepthtest.integer)
10326 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10327 GL_DepthMask(false);
10331 GL_BlendFunc(GL_ONE, GL_ZERO);
10332 GL_DepthMask(true);
10334 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10336 if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10338 rsurface.texture = R_GetCurrentTexture(surface->texture);
10339 if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10341 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
10342 qglBegin(GL_LINES);
10343 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
10345 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10347 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10348 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10349 qglVertex3f(v[0], v[1], v[2]);
10350 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10351 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10352 qglVertex3f(v[0], v[1], v[2]);
10355 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
10357 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10359 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10360 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
10361 qglVertex3f(v[0], v[1], v[2]);
10362 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
10363 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10364 qglVertex3f(v[0], v[1], v[2]);
10367 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
10369 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10371 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10372 GL_Color(0, r_refdef.view.colorscale, 0, 1);
10373 qglVertex3f(v[0], v[1], v[2]);
10374 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
10375 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10376 qglVertex3f(v[0], v[1], v[2]);
10379 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
10381 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10383 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10384 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10385 qglVertex3f(v[0], v[1], v[2]);
10386 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10387 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10388 qglVertex3f(v[0], v[1], v[2]);
10395 rsurface.texture = NULL;
10401 int r_maxsurfacelist = 0;
10402 const msurface_t **r_surfacelist = NULL;
10403 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass)
10405 int i, j, endj, flagsmask;
10406 dp_model_t *model = ent->model;
10407 msurface_t *surfaces;
10408 unsigned char *update;
10409 int numsurfacelist = 0;
10413 if (r_maxsurfacelist < model->num_surfaces)
10415 r_maxsurfacelist = model->num_surfaces;
10417 Mem_Free((msurface_t **)r_surfacelist);
10418 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
10421 if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
10422 RSurf_ActiveModelEntity(ent, false, false, false);
10424 RSurf_ActiveModelEntity(ent, true, true, true);
10425 else if (depthonly)
10426 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
10428 RSurf_ActiveModelEntity(ent, true, true, false);
10430 surfaces = model->data_surfaces;
10431 update = model->brushq1.lightmapupdateflags;
10433 // update light styles
10434 if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0)
10436 model_brush_lightstyleinfo_t *style;
10437 for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
10439 if (style->value != r_refdef.scene.lightstylevalue[style->style])
10441 int *list = style->surfacelist;
10442 style->value = r_refdef.scene.lightstylevalue[style->style];
10443 for (j = 0;j < style->numsurfaces;j++)
10444 update[list[j]] = true;
10449 flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
10453 R_DrawDebugModel();
10454 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10458 rsurface.lightmaptexture = NULL;
10459 rsurface.deluxemaptexture = NULL;
10460 rsurface.uselightmaptexture = false;
10461 rsurface.texture = NULL;
10462 rsurface.rtlight = NULL;
10463 numsurfacelist = 0;
10464 // add visible surfaces to draw list
10465 if (ent == r_refdef.scene.worldentity)
10467 // for the world entity, check surfacevisible
10468 for (i = 0;i < model->nummodelsurfaces;i++)
10470 j = model->sortedmodelsurfaces[i];
10471 if (r_refdef.viewcache.world_surfacevisible[j])
10472 r_surfacelist[numsurfacelist++] = surfaces + j;
10477 // add all surfaces
10478 for (i = 0; i < model->nummodelsurfaces; i++)
10479 r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
10481 // don't do anything if there were no surfaces
10482 if (!numsurfacelist)
10484 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10487 // update lightmaps if needed
10491 for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
10496 R_BuildLightMap(ent, surfaces + j);
10501 R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass);
10503 // add to stats if desired
10504 if (r_speeds.integer && !skysurfaces && !depthonly)
10506 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10507 for (j = 0;j < numsurfacelist;j++)
10508 r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10511 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10514 void R_DebugLine(vec3_t start, vec3_t end)
10516 dp_model_t *mod = CL_Mesh_UI();
10518 int e0, e1, e2, e3;
10519 float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10520 float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10521 float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10524 // transform to screen coords first
10525 Vector4Set(w[0], start[0], start[1], start[2], 1);
10526 Vector4Set(w[1], end[0], end[1], end[2], 1);
10527 R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10528 R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10529 x1 = s[0][0] * vid_conwidth.value / vid.width;
10530 y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10531 x2 = s[1][0] * vid_conwidth.value / vid.width;
10532 y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10533 //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10535 // add the line to the UI mesh for drawing later
10537 // width is measured in real pixels
10538 if (fabs(x2 - x1) > fabs(y2 - y1))
10541 offsety = 0.5f * width * vid_conheight.value / vid.height;
10545 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10548 surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_VERTEXCOLOR), true);
10549 e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10550 e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10551 e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10552 e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10553 Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10554 Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10559 void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass)
10562 static texture_t texture;
10563 static msurface_t surface;
10564 const msurface_t *surfacelist = &surface;
10566 // fake enough texture and surface state to render this geometry
10568 texture.update_lastrenderframe = -1; // regenerate this texture
10569 texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10570 texture.basealpha = 1.0f;
10571 texture.currentskinframe = skinframe;
10572 texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10573 texture.offsetmapping = OFFSETMAPPING_OFF;
10574 texture.offsetscale = 1;
10575 texture.specularscalemod = 1;
10576 texture.specularpowermod = 1;
10577 texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10578 // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
10579 // JUST GREP FOR "specularscalemod = 1".
10581 for (q = 0; q < 3; q++)
10583 texture.render_glowmod[q] = r_refdef.view.colorscale * r_hdr_glowintensity.value;
10584 texture.render_modellight_lightdir[q] = q == 2;
10585 texture.render_modellight_ambient[q] = r_refdef.view.colorscale * r_refdef.scene.ambientintensity;
10586 texture.render_modellight_diffuse[q] = r_refdef.view.colorscale;
10587 texture.render_modellight_specular[q] = r_refdef.view.colorscale;
10588 texture.render_lightmap_ambient[q] = r_refdef.view.colorscale * r_refdef.scene.ambientintensity;
10589 texture.render_lightmap_diffuse[q] = r_refdef.view.colorscale * r_refdef.scene.lightmapintensity;
10590 texture.render_lightmap_specular[q] = r_refdef.view.colorscale;
10591 texture.render_rtlight_diffuse[q] = r_refdef.view.colorscale;
10592 texture.render_rtlight_specular[q] = r_refdef.view.colorscale;
10594 texture.currentalpha = 1.0f;
10596 surface.texture = &texture;
10597 surface.num_triangles = numtriangles;
10598 surface.num_firsttriangle = firsttriangle;
10599 surface.num_vertices = numvertices;
10600 surface.num_firstvertex = firstvertex;
10603 rsurface.texture = R_GetCurrentTexture(surface.texture);
10604 rsurface.lightmaptexture = NULL;
10605 rsurface.deluxemaptexture = NULL;
10606 rsurface.uselightmaptexture = false;
10607 R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);
10610 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)
10612 static msurface_t surface;
10613 const msurface_t *surfacelist = &surface;
10615 // fake enough texture and surface state to render this geometry
10616 surface.texture = texture;
10617 surface.num_triangles = numtriangles;
10618 surface.num_firsttriangle = firsttriangle;
10619 surface.num_vertices = numvertices;
10620 surface.num_firstvertex = firstvertex;
10623 rsurface.texture = R_GetCurrentTexture(surface.texture);
10624 rsurface.lightmaptexture = NULL;
10625 rsurface.deluxemaptexture = NULL;
10626 rsurface.uselightmaptexture = false;
10627 R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);