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];
4550 //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
4551 rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
4553 if (!r_refdef.view.useperspective)
4554 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);
4555 else if (vid.stencil && r_useinfinitefarclip.integer)
4556 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);
4558 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);
4559 R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4560 R_SetViewport(&r_refdef.view.viewport);
4563 void R_EntityMatrix(const matrix4x4_t *matrix)
4565 if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4567 gl_modelmatrixchanged = false;
4568 gl_modelmatrix = *matrix;
4569 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4570 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4571 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4572 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4574 switch(vid.renderpath)
4576 case RENDERPATH_GL20:
4577 case RENDERPATH_GLES2:
4578 if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4579 if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4585 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4587 r_viewport_t viewport;
4591 // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
4592 R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4593 R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4594 R_SetViewport(&viewport);
4595 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4596 GL_Color(1, 1, 1, 1);
4597 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4598 GL_BlendFunc(GL_ONE, GL_ZERO);
4599 GL_ScissorTest(false);
4600 GL_DepthMask(false);
4601 GL_DepthRange(0, 1);
4602 GL_DepthTest(false);
4603 GL_DepthFunc(GL_LEQUAL);
4604 R_EntityMatrix(&identitymatrix);
4605 R_Mesh_ResetTextureState();
4606 GL_PolygonOffset(0, 0);
4607 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
4608 switch(vid.renderpath)
4610 case RENDERPATH_GL20:
4611 case RENDERPATH_GLES2:
4612 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4615 GL_CullFace(GL_NONE);
4620 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4622 R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4625 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4627 R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4628 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4629 GL_Color(1, 1, 1, 1);
4630 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4631 GL_BlendFunc(GL_ONE, GL_ZERO);
4632 GL_ScissorTest(true);
4634 GL_DepthRange(0, 1);
4636 GL_DepthFunc(GL_LEQUAL);
4637 R_EntityMatrix(&identitymatrix);
4638 R_Mesh_ResetTextureState();
4639 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4640 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
4641 switch(vid.renderpath)
4643 case RENDERPATH_GL20:
4644 case RENDERPATH_GLES2:
4645 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4648 GL_CullFace(r_refdef.view.cullface_back);
4653 R_RenderView_UpdateViewVectors
4656 void R_RenderView_UpdateViewVectors(void)
4658 // break apart the view matrix into vectors for various purposes
4659 // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4660 // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4661 Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4662 VectorNegate(r_refdef.view.left, r_refdef.view.right);
4663 // make an inverted copy of the view matrix for tracking sprites
4664 Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4667 void R_RenderTarget_FreeUnused(qboolean force)
4670 end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
4671 for (i = 0; i < end; i++)
4673 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4674 // free resources for rendertargets that have not been used for a while
4675 // (note: this check is run after the frame render, so any targets used
4676 // this frame will not be affected even at low framerates)
4677 if (r && (realtime - r->lastusetime > 0.2 || force))
4680 R_Mesh_DestroyFramebufferObject(r->fbo);
4681 for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4682 if (r->colortexture[j])
4683 R_FreeTexture(r->colortexture[j]);
4684 if (r->depthtexture)
4685 R_FreeTexture(r->depthtexture);
4686 Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4691 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4693 float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4697 y2 = (th - y - h) * ih;
4708 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)
4711 r_rendertarget_t *r = NULL;
4713 // first try to reuse an existing slot if possible
4714 end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
4715 for (i = 0; i < end; i++)
4717 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4718 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)
4723 // no unused exact match found, so we have to make one in the first unused slot
4724 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4725 r->texturewidth = texturewidth;
4726 r->textureheight = textureheight;
4727 r->colortextype[0] = colortextype0;
4728 r->colortextype[1] = colortextype1;
4729 r->colortextype[2] = colortextype2;
4730 r->colortextype[3] = colortextype3;
4731 r->depthtextype = depthtextype;
4732 r->depthisrenderbuffer = depthisrenderbuffer;
4733 for (j = 0; j < 4; j++)
4734 if (r->colortextype[j])
4735 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);
4736 if (r->depthtextype)
4738 if (r->depthisrenderbuffer)
4739 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);
4741 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);
4743 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4745 r_refdef.stats[r_stat_rendertargets_used]++;
4746 r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4747 r->lastusetime = realtime;
4748 R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4752 static void R_Water_StartFrame(void)
4754 int waterwidth, waterheight;
4756 if (vid.width > (int)vid.maxtexturesize_2d || vid.height > (int)vid.maxtexturesize_2d)
4759 // set waterwidth and waterheight to the water resolution that will be
4760 // used (often less than the screen resolution for faster rendering)
4761 waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width);
4762 waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height);
4763 R_GetScaledViewSize(waterwidth, waterheight, &waterwidth, &waterheight);
4765 if (!r_water.integer || r_showsurfaces.integer)
4766 waterwidth = waterheight = 0;
4768 // set up variables that will be used in shader setup
4769 r_fb.water.waterwidth = waterwidth;
4770 r_fb.water.waterheight = waterheight;
4771 r_fb.water.texturewidth = waterwidth;
4772 r_fb.water.textureheight = waterheight;
4773 r_fb.water.camerawidth = waterwidth;
4774 r_fb.water.cameraheight = waterheight;
4775 r_fb.water.screenscale[0] = 0.5f;
4776 r_fb.water.screenscale[1] = 0.5f;
4777 r_fb.water.screencenter[0] = 0.5f;
4778 r_fb.water.screencenter[1] = 0.5f;
4779 r_fb.water.enabled = waterwidth != 0;
4781 r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4782 r_fb.water.numwaterplanes = 0;
4785 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4787 int planeindex, bestplaneindex, vertexindex;
4788 vec3_t mins, maxs, normal, center, v, n;
4789 vec_t planescore, bestplanescore;
4791 r_waterstate_waterplane_t *p;
4792 texture_t *t = R_GetCurrentTexture(surface->texture);
4794 rsurface.texture = t;
4795 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4796 // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4797 if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4799 // average the vertex normals, find the surface bounds (after deformvertexes)
4800 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4801 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4802 VectorCopy(n, normal);
4803 VectorCopy(v, mins);
4804 VectorCopy(v, maxs);
4805 for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4807 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4808 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4809 VectorAdd(normal, n, normal);
4810 mins[0] = min(mins[0], v[0]);
4811 mins[1] = min(mins[1], v[1]);
4812 mins[2] = min(mins[2], v[2]);
4813 maxs[0] = max(maxs[0], v[0]);
4814 maxs[1] = max(maxs[1], v[1]);
4815 maxs[2] = max(maxs[2], v[2]);
4817 VectorNormalize(normal);
4818 VectorMAM(0.5f, mins, 0.5f, maxs, center);
4820 VectorCopy(normal, plane.normal);
4821 VectorNormalize(plane.normal);
4822 plane.dist = DotProduct(center, plane.normal);
4823 PlaneClassify(&plane);
4824 if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4826 // skip backfaces (except if nocullface is set)
4827 // if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4829 VectorNegate(plane.normal, plane.normal);
4831 PlaneClassify(&plane);
4835 // find a matching plane if there is one
4836 bestplaneindex = -1;
4837 bestplanescore = 1048576.0f;
4838 for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4840 if(p->camera_entity == t->camera_entity)
4842 planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4843 if (bestplaneindex < 0 || bestplanescore > planescore)
4845 bestplaneindex = planeindex;
4846 bestplanescore = planescore;
4850 planeindex = bestplaneindex;
4852 // if this surface does not fit any known plane rendered this frame, add one
4853 if (planeindex < 0 || bestplanescore > 0.001f)
4855 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4857 // store the new plane
4858 planeindex = r_fb.water.numwaterplanes++;
4859 p = r_fb.water.waterplanes + planeindex;
4861 // clear materialflags and pvs
4862 p->materialflags = 0;
4863 p->pvsvalid = false;
4864 p->camera_entity = t->camera_entity;
4865 VectorCopy(mins, p->mins);
4866 VectorCopy(maxs, p->maxs);
4870 // We're totally screwed.
4876 // merge mins/maxs when we're adding this surface to the plane
4877 p = r_fb.water.waterplanes + planeindex;
4878 p->mins[0] = min(p->mins[0], mins[0]);
4879 p->mins[1] = min(p->mins[1], mins[1]);
4880 p->mins[2] = min(p->mins[2], mins[2]);
4881 p->maxs[0] = max(p->maxs[0], maxs[0]);
4882 p->maxs[1] = max(p->maxs[1], maxs[1]);
4883 p->maxs[2] = max(p->maxs[2], maxs[2]);
4885 // merge this surface's materialflags into the waterplane
4886 p->materialflags |= t->currentmaterialflags;
4887 if(!(p->materialflags & MATERIALFLAG_CAMERA))
4889 // merge this surface's PVS into the waterplane
4890 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4891 && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4893 r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4899 extern cvar_t r_drawparticles;
4900 extern cvar_t r_drawdecals;
4902 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4905 r_refdef_view_t originalview;
4906 r_refdef_view_t myview;
4907 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;
4908 r_waterstate_waterplane_t *p;
4910 r_rendertarget_t *rt;
4912 originalview = r_refdef.view;
4914 // lowquality hack, temporarily shut down some cvars and restore afterwards
4915 qualityreduction = r_water_lowquality.integer;
4916 if (qualityreduction > 0)
4918 if (qualityreduction >= 1)
4920 old_r_shadows = r_shadows.integer;
4921 old_r_worldrtlight = r_shadow_realtime_world.integer;
4922 old_r_dlight = r_shadow_realtime_dlight.integer;
4923 Cvar_SetValueQuick(&r_shadows, 0);
4924 Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4925 Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4927 if (qualityreduction >= 2)
4929 old_r_dynamic = r_dynamic.integer;
4930 old_r_particles = r_drawparticles.integer;
4931 old_r_decals = r_drawdecals.integer;
4932 Cvar_SetValueQuick(&r_dynamic, 0);
4933 Cvar_SetValueQuick(&r_drawparticles, 0);
4934 Cvar_SetValueQuick(&r_drawdecals, 0);
4938 for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4940 p->rt_reflection = NULL;
4941 p->rt_refraction = NULL;
4942 p->rt_camera = NULL;
4946 r_refdef.view = originalview;
4947 r_refdef.view.showdebug = false;
4948 r_refdef.view.width = r_fb.water.waterwidth;
4949 r_refdef.view.height = r_fb.water.waterheight;
4950 r_refdef.view.useclipplane = true;
4951 myview = r_refdef.view;
4952 r_fb.water.renderingscene = true;
4953 for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4955 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4958 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4960 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);
4961 if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4963 r_refdef.view = myview;
4964 Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4965 Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4966 if(r_water_scissormode.integer)
4968 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4969 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4971 p->rt_reflection = NULL;
4972 p->rt_refraction = NULL;
4973 p->rt_camera = NULL;
4978 r_refdef.view.clipplane = p->plane;
4979 // reflected view origin may be in solid, so don't cull with it
4980 r_refdef.view.usevieworiginculling = false;
4981 // reverse the cullface settings for this render
4982 r_refdef.view.cullface_front = GL_FRONT;
4983 r_refdef.view.cullface_back = GL_BACK;
4984 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4986 r_refdef.view.usecustompvs = true;
4988 memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4990 memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4993 r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4994 R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4995 GL_ScissorTest(false);
4996 R_ClearScreen(r_refdef.fogenabled);
4997 GL_ScissorTest(true);
4998 if(r_water_scissormode.integer & 2)
4999 R_View_UpdateWithScissor(myscissor);
5002 R_AnimCache_CacheVisibleEntities();
5003 if(r_water_scissormode.integer & 1)
5004 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
5005 R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5007 r_fb.water.hideplayer = false;
5008 p->rt_reflection = rt;
5011 // render the normal view scene and copy into texture
5012 // (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)
5013 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
5015 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);
5016 if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5018 r_refdef.view = myview;
5019 if(r_water_scissormode.integer)
5021 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
5022 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
5024 p->rt_reflection = NULL;
5025 p->rt_refraction = NULL;
5026 p->rt_camera = NULL;
5031 r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
5033 r_refdef.view.clipplane = p->plane;
5034 VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5035 r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5037 if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
5039 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5040 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
5041 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5042 R_RenderView_UpdateViewVectors();
5043 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5045 r_refdef.view.usecustompvs = true;
5046 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);
5050 PlaneClassify(&r_refdef.view.clipplane);
5052 R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5053 GL_ScissorTest(false);
5054 R_ClearScreen(r_refdef.fogenabled);
5055 GL_ScissorTest(true);
5056 if(r_water_scissormode.integer & 2)
5057 R_View_UpdateWithScissor(myscissor);
5060 R_AnimCache_CacheVisibleEntities();
5061 if(r_water_scissormode.integer & 1)
5062 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
5063 R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5065 r_fb.water.hideplayer = false;
5066 p->rt_refraction = rt;
5068 else if (p->materialflags & MATERIALFLAG_CAMERA)
5070 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);
5071 if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5073 r_refdef.view = myview;
5075 r_refdef.view.clipplane = p->plane;
5076 VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5077 r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5079 r_refdef.view.width = r_fb.water.camerawidth;
5080 r_refdef.view.height = r_fb.water.cameraheight;
5081 r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
5082 r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
5083 r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
5084 r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
5086 if(p->camera_entity)
5088 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5089 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5092 // note: all of the view is used for displaying... so
5093 // there is no use in scissoring
5095 // reverse the cullface settings for this render
5096 r_refdef.view.cullface_front = GL_FRONT;
5097 r_refdef.view.cullface_back = GL_BACK;
5098 // also reverse the view matrix
5099 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
5100 R_RenderView_UpdateViewVectors();
5101 if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5103 r_refdef.view.usecustompvs = true;
5104 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);
5107 // camera needs no clipplane
5108 r_refdef.view.useclipplane = false;
5109 // TODO: is the camera origin always valid? if so we don't need to clear this
5110 r_refdef.view.usevieworiginculling = false;
5112 PlaneClassify(&r_refdef.view.clipplane);
5114 r_fb.water.hideplayer = false;
5116 R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5117 GL_ScissorTest(false);
5118 R_ClearScreen(r_refdef.fogenabled);
5119 GL_ScissorTest(true);
5121 R_AnimCache_CacheVisibleEntities();
5122 R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5124 r_fb.water.hideplayer = false;
5129 r_fb.water.renderingscene = false;
5130 r_refdef.view = originalview;
5131 R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5133 R_AnimCache_CacheVisibleEntities();
5136 r_refdef.view = originalview;
5137 r_fb.water.renderingscene = false;
5138 Cvar_SetValueQuick(&r_water, 0);
5139 Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed! Turned off r_water.\n");
5141 // lowquality hack, restore cvars
5142 if (qualityreduction > 0)
5144 if (qualityreduction >= 1)
5146 Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5147 Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5148 Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5150 if (qualityreduction >= 2)
5152 Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5153 Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5154 Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5159 static void R_Bloom_StartFrame(void)
5161 int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
5162 int viewwidth, viewheight;
5163 textype_t textype = TEXTYPE_COLORBUFFER;
5165 // clear the pointers to rendertargets from last frame as they're stale
5166 r_fb.rt_screen = NULL;
5167 r_fb.rt_bloom = NULL;
5169 switch (vid.renderpath)
5171 case RENDERPATH_GL20:
5172 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5173 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5174 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5175 // for simplicity, bloom requires FBO render to texture, which basically all video drivers support now
5176 if (!vid.support.ext_framebuffer_object)
5179 case RENDERPATH_GLES2:
5180 r_fb.usedepthtextures = false;
5184 if (r_viewscale_fpsscaling.integer)
5186 double actualframetime;
5187 double targetframetime;
5189 actualframetime = r_refdef.lastdrawscreentime;
5190 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5191 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5192 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5193 if (r_viewscale_fpsscaling_stepsize.value > 0)
5194 adjust = (int)(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5195 viewscalefpsadjusted += adjust;
5196 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5199 viewscalefpsadjusted = 1.0f;
5201 R_GetScaledViewSize(r_refdef.view.width, r_refdef.view.height, &viewwidth, &viewheight);
5203 // set bloomwidth and bloomheight to the bloom resolution that will be
5204 // used (often less than the screen resolution for faster rendering)
5205 r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, vid.width);
5206 r_fb.bloomheight = r_fb.bloomwidth * vid.height / vid.width;
5207 r_fb.bloomheight = bound(1, r_fb.bloomheight, vid.height);
5208 r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5209 r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5211 // calculate desired texture sizes
5212 screentexturewidth = viewwidth;
5213 screentextureheight = viewheight;
5214 bloomtexturewidth = r_fb.bloomwidth;
5215 bloomtextureheight = r_fb.bloomheight;
5217 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))
5219 Cvar_SetValueQuick(&r_bloom, 0);
5220 Cvar_SetValueQuick(&r_motionblur, 0);
5221 Cvar_SetValueQuick(&r_damageblur, 0);
5224 // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5225 if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5227 if (r_fb.ghosttexture)
5228 R_FreeTexture(r_fb.ghosttexture);
5229 r_fb.ghosttexture = NULL;
5231 r_fb.screentexturewidth = screentexturewidth;
5232 r_fb.screentextureheight = screentextureheight;
5233 r_fb.textype = textype;
5235 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5237 if (r_motionblur.value > 0 || r_damageblur.value > 0)
5238 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);
5239 r_fb.ghosttexture_valid = false;
5243 if (r_bloom.integer)
5245 // bloom texture is a different resolution
5246 r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.width);
5247 r_fb.bloomheight = r_fb.bloomwidth * r_refdef.view.height / r_refdef.view.width;
5248 r_fb.bloomheight = bound(1, r_fb.bloomheight, r_refdef.view.height);
5251 r_fb.bloomwidth = r_fb.bloomheight = 0;
5253 r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5255 r_refdef.view.clear = true;
5258 static void R_Bloom_MakeTexture(void)
5261 float xoffset, yoffset, r, brighten;
5262 float colorscale = r_bloom_colorscale.value;
5263 r_viewport_t bloomviewport;
5264 r_rendertarget_t *prev, *cur;
5265 textype_t textype = r_fb.rt_screen->colortextype[0];
5267 r_refdef.stats[r_stat_bloom]++;
5269 R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5271 // scale down screen texture to the bloom texture size
5273 prev = r_fb.rt_screen;
5274 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5275 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5276 R_SetViewport(&bloomviewport);
5277 GL_CullFace(GL_NONE);
5278 GL_DepthTest(false);
5279 GL_BlendFunc(GL_ONE, GL_ZERO);
5280 GL_Color(colorscale, colorscale, colorscale, 1);
5281 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5282 // TODO: do boxfilter scale-down in shader?
5283 R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, true);
5284 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5285 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5286 // we now have a properly scaled bloom image
5288 // multiply bloom image by itself as many times as desired to darken it
5289 // TODO: if people actually use this it could be done more quickly in the previous shader pass
5290 for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5293 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5294 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5296 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5298 GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128);
5299 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5300 GL_Color(1,1,1,1); // no fix factor supported here
5301 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5302 R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, false);
5303 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5304 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5307 range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5308 brighten = r_bloom_brighten.value;
5309 brighten = sqrt(brighten);
5311 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5313 for (dir = 0;dir < 2;dir++)
5316 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5317 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5318 // blend on at multiple vertical offsets to achieve a vertical blur
5319 // TODO: do offset blends using GLSL
5320 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5321 GL_BlendFunc(GL_ONE, GL_ZERO);
5322 R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, false);
5323 for (x = -range;x <= range;x++)
5325 if (!dir){xoffset = 0;yoffset = x;}
5326 else {xoffset = x;yoffset = 0;}
5327 xoffset /= (float)prev->texturewidth;
5328 yoffset /= (float)prev->textureheight;
5329 // compute a texcoord array with the specified x and y offset
5330 r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5331 r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5332 r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5333 r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5334 r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5335 r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5336 r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5337 r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5338 // this r value looks like a 'dot' particle, fading sharply to
5339 // black at the edges
5340 // (probably not realistic but looks good enough)
5341 //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5342 //r = brighten/(range*2+1);
5343 r = brighten / (range * 2 + 1);
5345 r *= (1 - x*x/(float)((range+1)*(range+1)));
5348 GL_Color(r, r, r, 1);
5349 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5350 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5351 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5352 GL_BlendFunc(GL_ONE, GL_ONE);
5356 // now we have the bloom image, so keep track of it
5357 r_fb.rt_bloom = cur;
5360 static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5362 dpuint64 permutation;
5363 float uservecs[4][4];
5364 rtexture_t *viewtexture;
5365 rtexture_t *bloomtexture;
5367 R_EntityMatrix(&identitymatrix);
5369 if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
5371 // declare variables
5372 float blur_factor, blur_mouseaccel, blur_velocity;
5373 static float blur_average;
5374 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5376 // set a goal for the factoring
5377 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value)
5378 / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5379 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value)
5380 / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5381 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value)
5382 + (blur_mouseaccel * r_motionblur_mousefactor.value));
5384 // from the goal, pick an averaged value between goal and last value
5385 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5386 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5388 // enforce minimum amount of blur
5389 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5391 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5393 // calculate values into a standard alpha
5394 cl.motionbluralpha = 1 - exp(-
5396 (r_motionblur.value * blur_factor / 80)
5398 (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5401 max(0.0001, cl.time - cl.oldtime) // fps independent
5404 // randomization for the blur value to combat persistent ghosting
5405 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5406 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5409 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5410 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5412 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5413 GL_Color(1, 1, 1, cl.motionbluralpha);
5414 R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5415 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5416 R_SetupShader_Generic(r_fb.ghosttexture, NULL, GL_MODULATE, 1, false, true, true);
5417 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5418 r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5421 // updates old view angles for next pass
5422 VectorCopy(cl.viewangles, blur_oldangles);
5424 // copy view into the ghost texture
5425 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5426 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5427 r_fb.ghosttexture_valid = true;
5430 if (r_fb.bloomwidth)
5432 // make the bloom texture
5433 R_Bloom_MakeTexture();
5436 #if _MSC_VER >= 1400
5437 #define sscanf sscanf_s
5439 memset(uservecs, 0, sizeof(uservecs));
5440 if (r_glsl_postprocess_uservec1_enable.integer)
5441 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5442 if (r_glsl_postprocess_uservec2_enable.integer)
5443 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5444 if (r_glsl_postprocess_uservec3_enable.integer)
5445 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5446 if (r_glsl_postprocess_uservec4_enable.integer)
5447 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5449 // render to the screen fbo
5450 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5451 GL_Color(1, 1, 1, 1);
5452 GL_BlendFunc(GL_ONE, GL_ZERO);
5454 viewtexture = r_fb.rt_screen->colortexture[0];
5455 bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5457 if (r_rendertarget_debug.integer >= 0)
5459 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5460 if (rt && rt->colortexture[0])
5462 viewtexture = rt->colortexture[0];
5463 bloomtexture = NULL;
5467 R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5468 switch(vid.renderpath)
5470 case RENDERPATH_GL20:
5471 case RENDERPATH_GLES2:
5473 (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5474 | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5475 | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5476 | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5477 | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5478 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5479 if (r_glsl_permutation->tex_Texture_First >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , viewtexture);
5480 if (r_glsl_permutation->tex_Texture_Second >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second , bloomtexture);
5481 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps );
5482 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]);
5483 if (r_glsl_permutation->loc_PixelSize >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5484 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]);
5485 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]);
5486 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]);
5487 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]);
5488 if (r_glsl_permutation->loc_Saturation >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation , r_glsl_saturation.value);
5489 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
5490 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);
5493 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5494 r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5497 matrix4x4_t r_waterscrollmatrix;
5499 void R_UpdateFog(void)
5502 if (gamemode == GAME_NEHAHRA)
5504 if (gl_fogenable.integer)
5506 r_refdef.oldgl_fogenable = true;
5507 r_refdef.fog_density = gl_fogdensity.value;
5508 r_refdef.fog_red = gl_fogred.value;
5509 r_refdef.fog_green = gl_foggreen.value;
5510 r_refdef.fog_blue = gl_fogblue.value;
5511 r_refdef.fog_alpha = 1;
5512 r_refdef.fog_start = 0;
5513 r_refdef.fog_end = gl_skyclip.value;
5514 r_refdef.fog_height = 1<<30;
5515 r_refdef.fog_fadedepth = 128;
5517 else if (r_refdef.oldgl_fogenable)
5519 r_refdef.oldgl_fogenable = false;
5520 r_refdef.fog_density = 0;
5521 r_refdef.fog_red = 0;
5522 r_refdef.fog_green = 0;
5523 r_refdef.fog_blue = 0;
5524 r_refdef.fog_alpha = 0;
5525 r_refdef.fog_start = 0;
5526 r_refdef.fog_end = 0;
5527 r_refdef.fog_height = 1<<30;
5528 r_refdef.fog_fadedepth = 128;
5533 r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5534 r_refdef.fog_start = max(0, r_refdef.fog_start);
5535 r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5537 if (r_refdef.fog_density && r_drawfog.integer)
5539 r_refdef.fogenabled = true;
5540 // this is the point where the fog reaches 0.9986 alpha, which we
5541 // consider a good enough cutoff point for the texture
5542 // (0.9986 * 256 == 255.6)
5543 if (r_fog_exp2.integer)
5544 r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5546 r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5547 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5548 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5549 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5550 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5551 R_BuildFogHeightTexture();
5552 // fog color was already set
5553 // update the fog texture
5554 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)
5555 R_BuildFogTexture();
5556 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5557 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5560 r_refdef.fogenabled = false;
5563 if (r_refdef.fog_density)
5565 r_refdef.fogcolor[0] = r_refdef.fog_red;
5566 r_refdef.fogcolor[1] = r_refdef.fog_green;
5567 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5569 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5570 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5571 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5572 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5576 VectorCopy(r_refdef.fogcolor, fogvec);
5577 // color.rgb *= ContrastBoost * SceneBrightness;
5578 VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5579 r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5580 r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5581 r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5586 void R_UpdateVariables(void)
5590 r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5592 r_refdef.farclip = r_farclip_base.value;
5593 if (r_refdef.scene.worldmodel)
5594 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5595 r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5597 if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5598 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5599 r_refdef.polygonfactor = 0;
5600 r_refdef.polygonoffset = 0;
5601 r_refdef.shadowpolygonfactor = r_refdef.polygonfactor + r_shadow_polygonfactor.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
5602 r_refdef.shadowpolygonoffset = r_refdef.polygonoffset + r_shadow_polygonoffset.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
5604 r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5605 r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5606 r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5607 r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5608 r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5609 if (FAKELIGHT_ENABLED)
5611 r_refdef.scene.lightmapintensity *= r_fakelight_intensity.value;
5613 else if (r_refdef.scene.worldmodel)
5615 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5617 if (r_showsurfaces.integer)
5619 r_refdef.scene.rtworld = false;
5620 r_refdef.scene.rtworldshadows = false;
5621 r_refdef.scene.rtdlight = false;
5622 r_refdef.scene.rtdlightshadows = false;
5623 r_refdef.scene.lightmapintensity = 0;
5626 r_gpuskeletal = false;
5627 switch(vid.renderpath)
5629 case RENDERPATH_GL20:
5630 r_gpuskeletal = vid.support.arb_uniform_buffer_object && r_glsl_skeletal.integer && !r_showsurfaces.integer; // FIXME add r_showsurfaces support to GLSL skeletal!
5631 case RENDERPATH_GLES2:
5632 if(!vid_gammatables_trivial)
5634 if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5636 // build GLSL gamma texture
5637 #define RAMPWIDTH 256
5638 unsigned short ramp[RAMPWIDTH * 3];
5639 unsigned char rampbgr[RAMPWIDTH][4];
5642 r_texture_gammaramps_serial = vid_gammatables_serial;
5644 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5645 for(i = 0; i < RAMPWIDTH; ++i)
5647 rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5648 rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5649 rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5652 if (r_texture_gammaramps)
5654 R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1);
5658 r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5664 // remove GLSL gamma texture
5670 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5671 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5677 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5678 if( scenetype != r_currentscenetype ) {
5679 // store the old scenetype
5680 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5681 r_currentscenetype = scenetype;
5682 // move in the new scene
5683 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5692 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5694 // of course, we could also add a qboolean that provides a lock state and a ReleaseScenePointer function..
5695 if( scenetype == r_currentscenetype ) {
5696 return &r_refdef.scene;
5698 return &r_scenes_store[ scenetype ];
5702 static int R_SortEntities_Compare(const void *ap, const void *bp)
5704 const entity_render_t *a = *(const entity_render_t **)ap;
5705 const entity_render_t *b = *(const entity_render_t **)bp;
5708 if(a->model < b->model)
5710 if(a->model > b->model)
5714 // TODO possibly calculate the REAL skinnum here first using
5716 if(a->skinnum < b->skinnum)
5718 if(a->skinnum > b->skinnum)
5721 // everything we compared is equal
5724 static void R_SortEntities(void)
5726 // below or equal 2 ents, sorting never gains anything
5727 if(r_refdef.scene.numentities <= 2)
5730 qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5738 extern cvar_t r_shadow_bouncegrid;
5739 extern cvar_t v_isometric;
5740 extern void V_MakeViewIsometric(void);
5741 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5743 matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5745 rtexture_t *viewdepthtexture = NULL;
5746 rtexture_t *viewcolortexture = NULL;
5747 int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5749 // finish any 2D rendering that was queued
5752 if (r_timereport_active)
5753 R_TimeReport("start");
5754 r_textureframe++; // used only by R_GetCurrentTexture
5755 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5757 if(R_CompileShader_CheckStaticParms())
5760 if (!r_drawentities.integer)
5761 r_refdef.scene.numentities = 0;
5762 else if (r_sortentities.integer)
5765 R_AnimCache_ClearCache();
5767 /* adjust for stereo display */
5768 if(R_Stereo_Active())
5770 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);
5771 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5774 if (r_refdef.view.isoverlay)
5776 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5777 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5778 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5779 R_TimeReport("depthclear");
5781 r_refdef.view.showdebug = false;
5783 r_fb.water.enabled = false;
5784 r_fb.water.numwaterplanes = 0;
5786 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5788 r_refdef.view.matrix = originalmatrix;
5794 if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5796 r_refdef.view.matrix = originalmatrix;
5800 r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5801 if (v_isometric.integer && r_refdef.view.ismain)
5802 V_MakeViewIsometric();
5804 r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5806 if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5807 // in sRGB fallback, behave similar to true sRGB: convert this
5808 // value from linear to sRGB
5809 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5811 R_RenderView_UpdateViewVectors();
5813 R_Shadow_UpdateWorldLightSelection();
5815 // this will set up r_fb.rt_screen
5816 R_Bloom_StartFrame();
5818 // apply bloom brightness offset
5820 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5822 // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5825 viewfbo = r_fb.rt_screen->fbo;
5826 viewdepthtexture = r_fb.rt_screen->depthtexture;
5827 viewcolortexture = r_fb.rt_screen->colortexture[0];
5831 viewheight = height;
5834 R_Water_StartFrame();
5837 if (r_timereport_active)
5838 R_TimeReport("viewsetup");
5840 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5842 // clear the whole fbo every frame - otherwise the driver will consider
5843 // it to be an inter-frame texture and stall in multi-gpu configurations
5845 GL_ScissorTest(false);
5846 R_ClearScreen(r_refdef.fogenabled);
5847 if (r_timereport_active)
5848 R_TimeReport("viewclear");
5850 r_refdef.view.clear = true;
5852 r_refdef.view.showdebug = true;
5855 if (r_timereport_active)
5856 R_TimeReport("visibility");
5858 R_AnimCache_CacheVisibleEntities();
5859 if (r_timereport_active)
5860 R_TimeReport("animcache");
5862 R_Shadow_UpdateBounceGridTexture();
5863 if (r_timereport_active && r_shadow_bouncegrid.integer)
5864 R_TimeReport("bouncegrid");
5866 r_fb.water.numwaterplanes = 0;
5867 if (r_fb.water.enabled)
5868 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5870 // for the actual view render we use scissoring a fair amount, so scissor
5871 // test needs to be on
5873 GL_ScissorTest(true);
5874 GL_Scissor(viewx, viewy, viewwidth, viewheight);
5875 R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5876 r_fb.water.numwaterplanes = 0;
5878 // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5879 GL_ScissorTest(false);
5881 R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
5882 if (r_timereport_active)
5883 R_TimeReport("blendview");
5885 r_refdef.view.matrix = originalmatrix;
5889 // go back to 2d rendering
5893 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5895 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5897 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5898 if (r_timereport_active)
5899 R_TimeReport("waterworld");
5902 // don't let sound skip if going slow
5903 if (r_refdef.scene.extraupdate)
5906 R_DrawModelsAddWaterPlanes();
5907 if (r_timereport_active)
5908 R_TimeReport("watermodels");
5910 if (r_fb.water.numwaterplanes)
5912 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5913 if (r_timereport_active)
5914 R_TimeReport("waterscenes");
5918 extern cvar_t cl_locs_show;
5919 static void R_DrawLocs(void);
5920 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5921 static void R_DrawModelDecals(void);
5922 extern cvar_t cl_decals_newsystem;
5923 extern qboolean r_shadow_usingdeferredprepass;
5924 extern int r_shadow_shadowmapatlas_modelshadows_size;
5925 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5927 qboolean shadowmapping = false;
5929 if (r_timereport_active)
5930 R_TimeReport("beginscene");
5932 r_refdef.stats[r_stat_renders]++;
5936 // don't let sound skip if going slow
5937 if (r_refdef.scene.extraupdate)
5940 R_MeshQueue_BeginScene();
5944 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);
5946 if (r_timereport_active)
5947 R_TimeReport("skystartframe");
5949 if (cl.csqc_vidvars.drawworld)
5951 // don't let sound skip if going slow
5952 if (r_refdef.scene.extraupdate)
5955 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5957 r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5958 if (r_timereport_active)
5959 R_TimeReport("worldsky");
5962 if (R_DrawBrushModelsSky() && r_timereport_active)
5963 R_TimeReport("bmodelsky");
5965 if (skyrendermasked && skyrenderlater)
5967 // we have to force off the water clipping plane while rendering sky
5968 R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5970 R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5971 if (r_timereport_active)
5972 R_TimeReport("sky");
5976 // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5977 r_shadow_viewfbo = viewfbo;
5978 r_shadow_viewdepthtexture = viewdepthtexture;
5979 r_shadow_viewcolortexture = viewcolortexture;
5980 r_shadow_viewx = viewx;
5981 r_shadow_viewy = viewy;
5982 r_shadow_viewwidth = viewwidth;
5983 r_shadow_viewheight = viewheight;
5985 R_Shadow_PrepareModelShadows();
5986 R_Shadow_PrepareLights();
5987 if (r_timereport_active)
5988 R_TimeReport("preparelights");
5990 // render all the shadowmaps that will be used for this view
5991 shadowmapping = R_Shadow_ShadowMappingEnabled();
5992 if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
5994 R_Shadow_DrawShadowMaps();
5995 if (r_timereport_active)
5996 R_TimeReport("shadowmaps");
5999 // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
6000 if (r_shadow_usingdeferredprepass)
6001 R_Shadow_DrawPrepass();
6003 // now we begin the forward pass of the view render
6004 if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
6006 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
6007 if (r_timereport_active)
6008 R_TimeReport("worlddepth");
6010 if (r_depthfirst.integer >= 2)
6012 R_DrawModelsDepth();
6013 if (r_timereport_active)
6014 R_TimeReport("modeldepth");
6017 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
6019 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
6020 if (r_timereport_active)
6021 R_TimeReport("world");
6024 // don't let sound skip if going slow
6025 if (r_refdef.scene.extraupdate)
6029 if (r_timereport_active)
6030 R_TimeReport("models");
6032 // don't let sound skip if going slow
6033 if (r_refdef.scene.extraupdate)
6036 if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && !r_shadows_drawafterrtlighting.integer && r_refdef.scene.lightmapintensity > 0)
6038 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6039 R_Shadow_DrawModelShadows();
6040 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6041 // don't let sound skip if going slow
6042 if (r_refdef.scene.extraupdate)
6046 if (!r_shadow_usingdeferredprepass)
6048 R_Shadow_DrawLights();
6049 if (r_timereport_active)
6050 R_TimeReport("rtlights");
6053 // don't let sound skip if going slow
6054 if (r_refdef.scene.extraupdate)
6057 if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && r_shadows_drawafterrtlighting.integer && r_refdef.scene.lightmapintensity > 0)
6059 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6060 R_Shadow_DrawModelShadows();
6061 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6062 // don't let sound skip if going slow
6063 if (r_refdef.scene.extraupdate)
6067 if (cl.csqc_vidvars.drawworld)
6069 if (cl_decals_newsystem.integer)
6071 R_DrawModelDecals();
6072 if (r_timereport_active)
6073 R_TimeReport("modeldecals");
6078 if (r_timereport_active)
6079 R_TimeReport("decals");
6083 if (r_timereport_active)
6084 R_TimeReport("particles");
6087 if (r_timereport_active)
6088 R_TimeReport("explosions");
6091 if (r_refdef.view.showdebug)
6093 if (cl_locs_show.integer)
6096 if (r_timereport_active)
6097 R_TimeReport("showlocs");
6100 if (r_drawportals.integer)
6103 if (r_timereport_active)
6104 R_TimeReport("portals");
6107 if (r_showbboxes_client.value > 0)
6109 R_DrawEntityBBoxes(CLVM_prog);
6110 if (r_timereport_active)
6111 R_TimeReport("clbboxes");
6113 if (r_showbboxes.value > 0)
6115 R_DrawEntityBBoxes(SVVM_prog);
6116 if (r_timereport_active)
6117 R_TimeReport("svbboxes");
6121 if (r_transparent.integer)
6123 R_MeshQueue_RenderTransparent();
6124 if (r_timereport_active)
6125 R_TimeReport("drawtrans");
6128 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))
6130 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
6131 if (r_timereport_active)
6132 R_TimeReport("worlddebug");
6133 R_DrawModelsDebug();
6134 if (r_timereport_active)
6135 R_TimeReport("modeldebug");
6138 if (cl.csqc_vidvars.drawworld)
6140 R_Shadow_DrawCoronas();
6141 if (r_timereport_active)
6142 R_TimeReport("coronas");
6145 // don't let sound skip if going slow
6146 if (r_refdef.scene.extraupdate)
6150 static const unsigned short bboxelements[36] =
6160 #define BBOXEDGES 13
6161 static const float bboxedges[BBOXEDGES][6] =
6164 { 0, 0, 0, 1, 1, 1 },
6166 { 0, 0, 0, 0, 1, 0 },
6167 { 0, 0, 0, 1, 0, 0 },
6168 { 0, 1, 0, 1, 1, 0 },
6169 { 1, 0, 0, 1, 1, 0 },
6171 { 0, 0, 1, 0, 1, 1 },
6172 { 0, 0, 1, 1, 0, 1 },
6173 { 0, 1, 1, 1, 1, 1 },
6174 { 1, 0, 1, 1, 1, 1 },
6176 { 0, 0, 0, 0, 0, 1 },
6177 { 1, 0, 0, 1, 0, 1 },
6178 { 0, 1, 0, 0, 1, 1 },
6179 { 1, 1, 0, 1, 1, 1 },
6182 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6184 int numvertices = BBOXEDGES * 8;
6185 float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6186 int numtriangles = BBOXEDGES * 12;
6187 unsigned short elements[BBOXEDGES * 36];
6189 float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6191 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6193 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6194 GL_DepthMask(false);
6195 GL_DepthRange(0, 1);
6196 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6198 for (edge = 0; edge < BBOXEDGES; edge++)
6200 for (i = 0; i < 3; i++)
6202 edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6203 edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6205 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6206 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6207 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6208 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6209 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6210 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6211 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6212 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6213 for (i = 0; i < 36; i++)
6214 elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6216 R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6217 if (r_refdef.fogenabled)
6219 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6221 f1 = RSurf_FogVertex(v);
6223 c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6224 c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6225 c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6228 R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6229 R_Mesh_ResetTextureState();
6230 R_SetupShader_Generic_NoTexture(false, false);
6231 R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6234 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6236 // hacky overloading of the parameters
6237 prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6240 prvm_edict_t *edict;
6242 GL_CullFace(GL_NONE);
6243 R_SetupShader_Generic_NoTexture(false, false);
6245 for (i = 0;i < numsurfaces;i++)
6247 edict = PRVM_EDICT_NUM(surfacelist[i]);
6248 switch ((int)PRVM_serveredictfloat(edict, solid))
6250 case SOLID_NOT: Vector4Set(color, 1, 1, 1, 0.05);break;
6251 case SOLID_TRIGGER: Vector4Set(color, 1, 0, 1, 0.10);break;
6252 case SOLID_BBOX: Vector4Set(color, 0, 1, 0, 0.10);break;
6253 case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6254 case SOLID_BSP: Vector4Set(color, 0, 0, 1, 0.05);break;
6255 case SOLID_CORPSE: Vector4Set(color, 1, 0.5, 0, 0.05);break;
6256 default: Vector4Set(color, 0, 0, 0, 0.50);break;
6258 if (prog == CLVM_prog)
6259 color[3] *= r_showbboxes_client.value;
6261 color[3] *= r_showbboxes.value;
6262 color[3] = bound(0, color[3], 1);
6263 GL_DepthTest(!r_showdisabledepthtest.integer);
6264 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6268 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6271 prvm_edict_t *edict;
6277 for (i = 0; i < prog->num_edicts; i++)
6279 edict = PRVM_EDICT_NUM(i);
6280 if (edict->priv.server->free)
6282 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6283 if (PRVM_serveredictedict(edict, tag_entity) != 0)
6285 if (PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6287 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6288 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6292 static const int nomodelelement3i[24] =
6304 static const unsigned short nomodelelement3s[24] =
6316 static const float nomodelvertex3f[6*3] =
6326 static const float nomodelcolor4f[6*4] =
6328 0.0f, 0.0f, 0.5f, 1.0f,
6329 0.0f, 0.0f, 0.5f, 1.0f,
6330 0.0f, 0.5f, 0.0f, 1.0f,
6331 0.0f, 0.5f, 0.0f, 1.0f,
6332 0.5f, 0.0f, 0.0f, 1.0f,
6333 0.5f, 0.0f, 0.0f, 1.0f
6336 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6342 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);
6344 // this is only called once per entity so numsurfaces is always 1, and
6345 // surfacelist is always {0}, so this code does not handle batches
6347 if (rsurface.ent_flags & RENDER_ADDITIVE)
6349 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6350 GL_DepthMask(false);
6352 else if (ent->alpha < 1)
6354 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6355 GL_DepthMask(false);
6359 GL_BlendFunc(GL_ONE, GL_ZERO);
6362 GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6363 GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6364 GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6365 GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6366 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6367 for (i = 0, c = color4f;i < 6;i++, c += 4)
6369 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6370 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6371 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6374 if (r_refdef.fogenabled)
6376 for (i = 0, c = color4f;i < 6;i++, c += 4)
6378 f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6380 c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6381 c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6382 c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6385 // R_Mesh_ResetTextureState();
6386 R_SetupShader_Generic_NoTexture(false, false);
6387 R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6388 R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6391 void R_DrawNoModel(entity_render_t *ent)
6394 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6395 if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6396 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6398 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6401 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6403 vec3_t right1, right2, diff, normal;
6405 VectorSubtract (org2, org1, normal);
6407 // calculate 'right' vector for start
6408 VectorSubtract (r_refdef.view.origin, org1, diff);
6409 CrossProduct (normal, diff, right1);
6410 VectorNormalize (right1);
6412 // calculate 'right' vector for end
6413 VectorSubtract (r_refdef.view.origin, org2, diff);
6414 CrossProduct (normal, diff, right2);
6415 VectorNormalize (right2);
6417 vert[ 0] = org1[0] + width * right1[0];
6418 vert[ 1] = org1[1] + width * right1[1];
6419 vert[ 2] = org1[2] + width * right1[2];
6420 vert[ 3] = org1[0] - width * right1[0];
6421 vert[ 4] = org1[1] - width * right1[1];
6422 vert[ 5] = org1[2] - width * right1[2];
6423 vert[ 6] = org2[0] - width * right2[0];
6424 vert[ 7] = org2[1] - width * right2[1];
6425 vert[ 8] = org2[2] - width * right2[2];
6426 vert[ 9] = org2[0] + width * right2[0];
6427 vert[10] = org2[1] + width * right2[1];
6428 vert[11] = org2[2] + width * right2[2];
6431 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)
6433 vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6434 vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6435 vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6436 vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6437 vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6438 vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6439 vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6440 vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6441 vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6442 vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6443 vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6444 vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6447 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6452 VectorSet(v, x, y, z);
6453 for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6454 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6456 if (i == mesh->numvertices)
6458 if (mesh->numvertices < mesh->maxvertices)
6460 VectorCopy(v, vertex3f);
6461 mesh->numvertices++;
6463 return mesh->numvertices;
6469 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6473 element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6474 element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6475 e = mesh->element3i + mesh->numtriangles * 3;
6476 for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6478 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6479 if (mesh->numtriangles < mesh->maxtriangles)
6484 mesh->numtriangles++;
6486 element[1] = element[2];
6490 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6494 element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6495 element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6496 e = mesh->element3i + mesh->numtriangles * 3;
6497 for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6499 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6500 if (mesh->numtriangles < mesh->maxtriangles)
6505 mesh->numtriangles++;
6507 element[1] = element[2];
6511 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6512 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6514 int planenum, planenum2;
6517 mplane_t *plane, *plane2;
6519 double temppoints[2][256*3];
6520 // figure out how large a bounding box we need to properly compute this brush
6522 for (w = 0;w < numplanes;w++)
6523 maxdist = max(maxdist, fabs(planes[w].dist));
6524 // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6525 maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6526 for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6530 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6531 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6533 if (planenum2 == planenum)
6535 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);
6538 if (tempnumpoints < 3)
6540 // generate elements forming a triangle fan for this polygon
6541 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6545 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)
6547 texturelayer_t *layer;
6548 layer = t->currentlayers + t->currentnumlayers++;
6550 layer->depthmask = depthmask;
6551 layer->blendfunc1 = blendfunc1;
6552 layer->blendfunc2 = blendfunc2;
6553 layer->texture = texture;
6554 layer->texmatrix = *matrix;
6555 layer->color[0] = r;
6556 layer->color[1] = g;
6557 layer->color[2] = b;
6558 layer->color[3] = a;
6561 static qboolean R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6563 if(parms[0] == 0 && parms[1] == 0)
6565 if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6566 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6571 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6574 index = parms[2] + rsurface.shadertime * parms[3];
6575 index -= floor(index);
6576 switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6579 case Q3WAVEFUNC_NONE:
6580 case Q3WAVEFUNC_NOISE:
6581 case Q3WAVEFUNC_COUNT:
6584 case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6585 case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6586 case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6587 case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6588 case Q3WAVEFUNC_TRIANGLE:
6590 f = index - floor(index);
6603 f = parms[0] + parms[1] * f;
6604 if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6605 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6609 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6616 matrix4x4_t matrix, temp;
6617 // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6618 // it's better to have one huge fixup every 9 hours than gradual
6619 // degradation over time which looks consistently bad after many hours.
6621 // tcmod scroll in particular suffers from this degradation which can't be
6622 // effectively worked around even with floor() tricks because we don't
6623 // know if tcmod scroll is the last tcmod being applied, and for clampmap
6624 // a workaround involving floor() would be incorrect anyway...
6625 shadertime = rsurface.shadertime;
6626 if (shadertime >= 32768.0f)
6627 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6628 switch(tcmod->tcmod)
6632 if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6633 matrix = r_waterscrollmatrix;
6635 matrix = identitymatrix;
6637 case Q3TCMOD_ENTITYTRANSLATE:
6638 // this is used in Q3 to allow the gamecode to control texcoord
6639 // scrolling on the entity, which is not supported in darkplaces yet.
6640 Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6642 case Q3TCMOD_ROTATE:
6643 Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6644 Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6645 Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6648 Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6650 case Q3TCMOD_SCROLL:
6651 // this particular tcmod is a "bug for bug" compatible one with regards to
6652 // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6653 // specifically did the wrapping and so we must mimic that...
6654 offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6655 offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6656 Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6658 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6659 w = (int) tcmod->parms[0];
6660 h = (int) tcmod->parms[1];
6661 f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6663 idx = (int) floor(f * w * h);
6664 Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6666 case Q3TCMOD_STRETCH:
6667 f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6668 Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6670 case Q3TCMOD_TRANSFORM:
6671 VectorSet(tcmat + 0, tcmod->parms[0], tcmod->parms[1], 0);
6672 VectorSet(tcmat + 3, tcmod->parms[2], tcmod->parms[3], 0);
6673 VectorSet(tcmat + 6, 0 , 0 , 1);
6674 VectorSet(tcmat + 9, tcmod->parms[4], tcmod->parms[5], 0);
6675 Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6677 case Q3TCMOD_TURBULENT:
6678 // this is handled in the RSurf_PrepareVertices function
6679 matrix = identitymatrix;
6683 Matrix4x4_Concat(texmatrix, &matrix, &temp);
6686 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6688 int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6689 char name[MAX_QPATH];
6690 skinframe_t *skinframe;
6691 unsigned char pixels[296*194];
6692 strlcpy(cache->name, skinname, sizeof(cache->name));
6693 dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6694 if (developer_loading.integer)
6695 Con_Printf("loading %s\n", name);
6696 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6697 if (!skinframe || !skinframe->base)
6700 fs_offset_t filesize;
6702 f = FS_LoadFile(name, tempmempool, true, &filesize);
6705 if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6706 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6710 cache->skinframe = skinframe;
6713 texture_t *R_GetCurrentTexture(texture_t *t)
6716 const entity_render_t *ent = rsurface.entity;
6717 dp_model_t *model = ent->model; // when calling this, ent must not be NULL
6718 q3shaderinfo_layer_tcmod_t *tcmod;
6719 float specularscale = 0.0f;
6721 if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6722 return t->currentframe;
6723 t->update_lastrenderframe = r_textureframe;
6724 t->update_lastrenderentity = (void *)ent;
6726 if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6727 t->camera_entity = ent->entitynumber;
6729 t->camera_entity = 0;
6731 // switch to an alternate material if this is a q1bsp animated material
6733 texture_t *texture = t;
6734 int s = rsurface.ent_skinnum;
6735 if ((unsigned int)s >= (unsigned int)model->numskins)
6737 if (model->skinscenes)
6739 if (model->skinscenes[s].framecount > 1)
6740 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6742 s = model->skinscenes[s].firstframe;
6745 t = t + s * model->num_surfaces;
6748 // use an alternate animation if the entity's frame is not 0,
6749 // and only if the texture has an alternate animation
6750 if (t->animated == 2) // q2bsp
6751 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6752 else if (rsurface.ent_alttextures && t->anim_total[1])
6753 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6755 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6757 texture->currentframe = t;
6760 // update currentskinframe to be a qw skin or animation frame
6761 if (rsurface.ent_qwskin >= 0)
6763 i = rsurface.ent_qwskin;
6764 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6766 r_qwskincache_size = cl.maxclients;
6768 Mem_Free(r_qwskincache);
6769 r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6771 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6772 R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6773 t->currentskinframe = r_qwskincache[i].skinframe;
6774 if (t->materialshaderpass && t->currentskinframe == NULL)
6775 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6777 else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6778 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6779 if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6780 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6782 t->currentmaterialflags = t->basematerialflags;
6783 t->currentalpha = rsurface.entity->alpha * t->basealpha;
6784 if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_novis.integer || r_trippy.integer))
6785 t->currentalpha *= r_wateralpha.value;
6786 if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6787 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6788 if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6789 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6791 // decide on which type of lighting to use for this surface
6792 if (rsurface.entity->render_modellight_forced)
6793 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6794 if (rsurface.entity->render_rtlight_disabled)
6795 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6796 if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6798 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6799 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT;
6800 for (q = 0; q < 3; q++)
6802 t->render_glowmod[q] = rsurface.entity->glowmod[q];
6803 t->render_modellight_lightdir[q] = q == 2;
6804 t->render_modellight_ambient[q] = 1;
6805 t->render_modellight_diffuse[q] = 0;
6806 t->render_modellight_specular[q] = 0;
6807 t->render_lightmap_ambient[q] = 0;
6808 t->render_lightmap_diffuse[q] = 0;
6809 t->render_lightmap_specular[q] = 0;
6810 t->render_rtlight_diffuse[q] = 0;
6811 t->render_rtlight_specular[q] = 0;
6814 else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6816 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6817 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT;
6818 for (q = 0; q < 3; q++)
6820 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6821 t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6822 t->render_modellight_lightdir[q] = q == 2;
6823 t->render_modellight_diffuse[q] = 0;
6824 t->render_modellight_specular[q] = 0;
6825 t->render_lightmap_ambient[q] = 0;
6826 t->render_lightmap_diffuse[q] = 0;
6827 t->render_lightmap_specular[q] = 0;
6828 t->render_rtlight_diffuse[q] = 0;
6829 t->render_rtlight_specular[q] = 0;
6832 else if (FAKELIGHT_ENABLED)
6834 // no modellight if using fakelight for the map
6835 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_NORTLIGHT) & ~(MATERIALFLAG_MODELLIGHT);
6836 for (q = 0; q < 3; q++)
6838 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6839 t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6840 t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6841 t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6842 t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6843 t->render_lightmap_ambient[q] = 0;
6844 t->render_lightmap_diffuse[q] = 0;
6845 t->render_lightmap_specular[q] = 0;
6846 t->render_rtlight_diffuse[q] = 0;
6847 t->render_rtlight_specular[q] = 0;
6850 else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6852 // ambient + single direction light (modellight)
6853 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6854 for (q = 0; q < 3; q++)
6856 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6857 t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6858 t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6859 t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6860 t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6861 t->render_lightmap_ambient[q] = 0;
6862 t->render_lightmap_diffuse[q] = 0;
6863 t->render_lightmap_specular[q] = 0;
6864 t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6865 t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6870 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6871 for (q = 0; q < 3; q++)
6873 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6874 t->render_modellight_lightdir[q] = q == 2;
6875 t->render_modellight_ambient[q] = 0;
6876 t->render_modellight_diffuse[q] = 0;
6877 t->render_modellight_specular[q] = 0;
6878 t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6879 t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6880 t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6881 t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6882 t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6886 if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6888 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6889 // attribute, we punt it to the lightmap path and hope for the best,
6890 // but lighting doesn't work.
6892 // FIXME: this is fine for effects but CSQC polygons should be subject
6894 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6895 for (q = 0; q < 3; q++)
6897 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6898 t->render_modellight_lightdir[q] = q == 2;
6899 t->render_modellight_ambient[q] = 0;
6900 t->render_modellight_diffuse[q] = 0;
6901 t->render_modellight_specular[q] = 0;
6902 t->render_lightmap_ambient[q] = 0;
6903 t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6904 t->render_lightmap_specular[q] = 0;
6905 t->render_rtlight_diffuse[q] = 0;
6906 t->render_rtlight_specular[q] = 0;
6910 for (q = 0; q < 3; q++)
6912 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6913 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6916 if (rsurface.ent_flags & RENDER_ADDITIVE)
6917 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6918 else if (t->currentalpha < 1)
6919 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6920 // LordHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6921 if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6922 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6923 if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6924 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6925 if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6926 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6927 if (t->backgroundshaderpass)
6928 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6929 if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6931 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6932 t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6935 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6936 if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6938 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6939 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6941 if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6942 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6944 // there is no tcmod
6945 if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6947 t->currenttexmatrix = r_waterscrollmatrix;
6948 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6950 else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6952 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6953 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6956 if (t->materialshaderpass)
6957 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6958 R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6960 t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6961 if (t->currentskinframe->qpixels)
6962 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6963 t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6964 if (!t->basetexture)
6965 t->basetexture = r_texture_notexture;
6966 t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6967 t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6968 t->nmaptexture = t->currentskinframe->nmap;
6969 if (!t->nmaptexture)
6970 t->nmaptexture = r_texture_blanknormalmap;
6971 t->glosstexture = r_texture_black;
6972 t->glowtexture = t->currentskinframe->glow;
6973 t->fogtexture = t->currentskinframe->fog;
6974 t->reflectmasktexture = t->currentskinframe->reflect;
6975 if (t->backgroundshaderpass)
6977 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6978 R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6979 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6980 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6981 t->backgroundglosstexture = r_texture_black;
6982 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6983 if (!t->backgroundnmaptexture)
6984 t->backgroundnmaptexture = r_texture_blanknormalmap;
6985 // make sure that if glow is going to be used, both textures are not NULL
6986 if (!t->backgroundglowtexture && t->glowtexture)
6987 t->backgroundglowtexture = r_texture_black;
6988 if (!t->glowtexture && t->backgroundglowtexture)
6989 t->glowtexture = r_texture_black;
6993 t->backgroundbasetexture = r_texture_white;
6994 t->backgroundnmaptexture = r_texture_blanknormalmap;
6995 t->backgroundglosstexture = r_texture_black;
6996 t->backgroundglowtexture = NULL;
6998 t->specularpower = r_shadow_glossexponent.value;
6999 // TODO: store reference values for these in the texture?
7000 if (r_shadow_gloss.integer > 0)
7002 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
7004 if (r_shadow_glossintensity.value > 0)
7006 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
7007 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
7008 specularscale = r_shadow_glossintensity.value;
7011 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
7013 t->glosstexture = r_texture_white;
7014 t->backgroundglosstexture = r_texture_white;
7015 specularscale = r_shadow_gloss2intensity.value;
7016 t->specularpower = r_shadow_gloss2exponent.value;
7019 specularscale *= t->specularscalemod;
7020 t->specularpower *= t->specularpowermod;
7022 // lightmaps mode looks bad with dlights using actual texturing, so turn
7023 // off the colormap and glossmap, but leave the normalmap on as it still
7024 // accurately represents the shading involved
7025 if (gl_lightmaps.integer)
7027 t->basetexture = r_texture_grey128;
7028 t->pantstexture = r_texture_black;
7029 t->shirttexture = r_texture_black;
7030 if (gl_lightmaps.integer < 2)
7031 t->nmaptexture = r_texture_blanknormalmap;
7032 t->glosstexture = r_texture_black;
7033 t->glowtexture = NULL;
7034 t->fogtexture = NULL;
7035 t->reflectmasktexture = NULL;
7036 t->backgroundbasetexture = NULL;
7037 if (gl_lightmaps.integer < 2)
7038 t->backgroundnmaptexture = r_texture_blanknormalmap;
7039 t->backgroundglosstexture = r_texture_black;
7040 t->backgroundglowtexture = NULL;
7042 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
7045 if (specularscale != 1.0f)
7047 for (q = 0; q < 3; q++)
7049 t->render_modellight_specular[q] *= specularscale;
7050 t->render_lightmap_specular[q] *= specularscale;
7051 t->render_rtlight_specular[q] *= specularscale;
7055 t->currentnumlayers = 0;
7056 if (t->currentmaterialflags & MATERIALFLAG_WALL)
7058 int blendfunc1, blendfunc2;
7060 if (t->currentmaterialflags & MATERIALFLAG_ADD)
7062 blendfunc1 = GL_SRC_ALPHA;
7063 blendfunc2 = GL_ONE;
7065 else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
7067 blendfunc1 = GL_SRC_ALPHA;
7068 blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
7070 else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
7072 blendfunc1 = t->customblendfunc[0];
7073 blendfunc2 = t->customblendfunc[1];
7077 blendfunc1 = GL_ONE;
7078 blendfunc2 = GL_ZERO;
7080 depthmask = !(t->currentmaterialflags & MATERIALFLAG_BLENDED);
7081 if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
7083 // basic lit geometry
7084 R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE, t->basetexture, &t->currenttexmatrix, 2, 2, 2, t->currentalpha);
7085 // add pants/shirt if needed
7086 if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7087 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);
7088 if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7089 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);
7093 // basic lit geometry
7094 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);
7095 // add pants/shirt if needed
7096 if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7097 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);
7098 if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7099 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);
7100 // now add ambient passes if needed
7101 if (VectorLength2(t->render_lightmap_ambient) >= (1.0f/1048576.0f))
7103 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);
7104 if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7105 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);
7106 if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7107 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);
7110 if (t->glowtexture != NULL && !gl_lightmaps.integer)
7111 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);
7112 if (r_refdef.fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD))
7114 // if this is opaque use alpha blend which will darken the earlier
7117 // if this is an alpha blended material, all the earlier passes
7118 // were darkened by fog already, so we only need to add the fog
7119 // color ontop through the fog mask texture
7121 // if this is an additive blended material, all the earlier passes
7122 // were darkened by fog already, and we should not add fog color
7123 // (because the background was not darkened, there is no fog color
7124 // that was lost behind it).
7125 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);
7132 rsurfacestate_t rsurface;
7134 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
7136 dp_model_t *model = ent->model;
7137 //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
7139 rsurface.entity = (entity_render_t *)ent;
7140 rsurface.skeleton = ent->skeleton;
7141 memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
7142 rsurface.ent_skinnum = ent->skinnum;
7143 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;
7144 rsurface.ent_flags = ent->flags;
7145 if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
7146 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
7147 rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
7148 rsurface.matrix = ent->matrix;
7149 rsurface.inversematrix = ent->inversematrix;
7150 rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7151 rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7152 R_EntityMatrix(&rsurface.matrix);
7153 Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7154 Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7155 rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
7156 rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7157 rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7158 rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7159 memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
7160 rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
7161 rsurface.basepolygonfactor = r_refdef.polygonfactor;
7162 rsurface.basepolygonoffset = r_refdef.polygonoffset;
7163 if (ent->model->brush.submodel && !prepass)
7165 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
7166 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
7168 // if the animcache code decided it should use the shader path, skip the deform step
7169 rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
7170 rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
7171 rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
7172 rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
7173 rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
7174 if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
7176 if (ent->animcache_vertex3f)
7178 r_refdef.stats[r_stat_batch_entitycache_count]++;
7179 r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
7180 r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
7181 r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
7182 rsurface.modelvertex3f = ent->animcache_vertex3f;
7183 rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
7184 rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
7185 rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
7186 rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
7187 rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
7188 rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
7189 rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
7190 rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
7191 rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
7192 rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
7193 rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
7194 rsurface.modelvertexmesh = ent->animcache_vertexmesh;
7195 rsurface.modelvertexmesh_vertexbuffer = ent->animcache_vertexmesh_vertexbuffer;
7196 rsurface.modelvertexmesh_bufferoffset = ent->animcache_vertexmesh_bufferoffset;
7198 else if (wanttangents)
7200 r_refdef.stats[r_stat_batch_entityanimate_count]++;
7201 r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7202 r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7203 r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7204 rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7205 rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7206 rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7207 rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7208 model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
7209 rsurface.modelvertexmesh = NULL;
7210 rsurface.modelvertexmesh_vertexbuffer = NULL;
7211 rsurface.modelvertexmesh_bufferoffset = 0;
7212 rsurface.modelvertex3f_vertexbuffer = NULL;
7213 rsurface.modelvertex3f_bufferoffset = 0;
7214 rsurface.modelvertex3f_vertexbuffer = 0;
7215 rsurface.modelvertex3f_bufferoffset = 0;
7216 rsurface.modelsvector3f_vertexbuffer = 0;
7217 rsurface.modelsvector3f_bufferoffset = 0;
7218 rsurface.modeltvector3f_vertexbuffer = 0;
7219 rsurface.modeltvector3f_bufferoffset = 0;
7220 rsurface.modelnormal3f_vertexbuffer = 0;
7221 rsurface.modelnormal3f_bufferoffset = 0;
7223 else if (wantnormals)
7225 r_refdef.stats[r_stat_batch_entityanimate_count]++;
7226 r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7227 r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7228 r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7229 rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7230 rsurface.modelsvector3f = NULL;
7231 rsurface.modeltvector3f = NULL;
7232 rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7233 model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
7234 rsurface.modelvertexmesh = NULL;
7235 rsurface.modelvertexmesh_vertexbuffer = NULL;
7236 rsurface.modelvertexmesh_bufferoffset = 0;
7237 rsurface.modelvertex3f_vertexbuffer = NULL;
7238 rsurface.modelvertex3f_bufferoffset = 0;
7239 rsurface.modelvertex3f_vertexbuffer = 0;
7240 rsurface.modelvertex3f_bufferoffset = 0;
7241 rsurface.modelsvector3f_vertexbuffer = 0;
7242 rsurface.modelsvector3f_bufferoffset = 0;
7243 rsurface.modeltvector3f_vertexbuffer = 0;
7244 rsurface.modeltvector3f_bufferoffset = 0;
7245 rsurface.modelnormal3f_vertexbuffer = 0;
7246 rsurface.modelnormal3f_bufferoffset = 0;
7250 r_refdef.stats[r_stat_batch_entityanimate_count]++;
7251 r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7252 r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7253 r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7254 rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7255 rsurface.modelsvector3f = NULL;
7256 rsurface.modeltvector3f = NULL;
7257 rsurface.modelnormal3f = NULL;
7258 model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7259 rsurface.modelvertexmesh = NULL;
7260 rsurface.modelvertexmesh_vertexbuffer = NULL;
7261 rsurface.modelvertexmesh_bufferoffset = 0;
7262 rsurface.modelvertex3f_vertexbuffer = NULL;
7263 rsurface.modelvertex3f_bufferoffset = 0;
7264 rsurface.modelvertex3f_vertexbuffer = 0;
7265 rsurface.modelvertex3f_bufferoffset = 0;
7266 rsurface.modelsvector3f_vertexbuffer = 0;
7267 rsurface.modelsvector3f_bufferoffset = 0;
7268 rsurface.modeltvector3f_vertexbuffer = 0;
7269 rsurface.modeltvector3f_bufferoffset = 0;
7270 rsurface.modelnormal3f_vertexbuffer = 0;
7271 rsurface.modelnormal3f_bufferoffset = 0;
7273 rsurface.modelgeneratedvertex = true;
7277 if (rsurface.entityskeletaltransform3x4)
7279 r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7280 r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7281 r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7282 r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7286 r_refdef.stats[r_stat_batch_entitystatic_count]++;
7287 r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7288 r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7289 r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7291 rsurface.modelvertex3f = model->surfmesh.data_vertex3f;
7292 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7293 rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
7294 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7295 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7296 rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f;
7297 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7298 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7299 rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f;
7300 rsurface.modelnormal3f = model->surfmesh.data_normal3f;
7301 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7302 rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f;
7303 rsurface.modelvertexmesh = model->surfmesh.data_vertexmesh;
7304 rsurface.modelvertexmesh_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7305 rsurface.modelvertexmesh_bufferoffset = model->surfmesh.vbooffset_vertex3f;
7306 rsurface.modelgeneratedvertex = false;
7308 rsurface.modellightmapcolor4f = model->surfmesh.data_lightmapcolor4f;
7309 rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7310 rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f;
7311 rsurface.modeltexcoordtexture2f = model->surfmesh.data_texcoordtexture2f;
7312 rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7313 rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f;
7314 rsurface.modeltexcoordlightmap2f = model->surfmesh.data_texcoordlightmap2f;
7315 rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7316 rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
7317 rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7318 rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7319 rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.vbooffset_skeletalindex4ub;
7320 rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7321 rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7322 rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.vbooffset_skeletalweight4ub;
7323 rsurface.modelelement3i = model->surfmesh.data_element3i;
7324 rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7325 rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7326 rsurface.modelelement3s = model->surfmesh.data_element3s;
7327 rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7328 rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7329 rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7330 rsurface.modelnumvertices = model->surfmesh.num_vertices;
7331 rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7332 rsurface.modelsurfaces = model->data_surfaces;
7333 rsurface.batchgeneratedvertex = false;
7334 rsurface.batchfirstvertex = 0;
7335 rsurface.batchnumvertices = 0;
7336 rsurface.batchfirsttriangle = 0;
7337 rsurface.batchnumtriangles = 0;
7338 rsurface.batchvertex3f = NULL;
7339 rsurface.batchvertex3f_vertexbuffer = NULL;
7340 rsurface.batchvertex3f_bufferoffset = 0;
7341 rsurface.batchsvector3f = NULL;
7342 rsurface.batchsvector3f_vertexbuffer = NULL;
7343 rsurface.batchsvector3f_bufferoffset = 0;
7344 rsurface.batchtvector3f = NULL;
7345 rsurface.batchtvector3f_vertexbuffer = NULL;
7346 rsurface.batchtvector3f_bufferoffset = 0;
7347 rsurface.batchnormal3f = NULL;
7348 rsurface.batchnormal3f_vertexbuffer = NULL;
7349 rsurface.batchnormal3f_bufferoffset = 0;
7350 rsurface.batchlightmapcolor4f = NULL;
7351 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7352 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7353 rsurface.batchtexcoordtexture2f = NULL;
7354 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7355 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7356 rsurface.batchtexcoordlightmap2f = NULL;
7357 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7358 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7359 rsurface.batchskeletalindex4ub = NULL;
7360 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7361 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7362 rsurface.batchskeletalweight4ub = NULL;
7363 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7364 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7365 rsurface.batchvertexmesh = NULL;
7366 rsurface.batchvertexmesh_vertexbuffer = NULL;
7367 rsurface.batchvertexmesh_bufferoffset = 0;
7368 rsurface.batchelement3i = NULL;
7369 rsurface.batchelement3i_indexbuffer = NULL;
7370 rsurface.batchelement3i_bufferoffset = 0;
7371 rsurface.batchelement3s = NULL;
7372 rsurface.batchelement3s_indexbuffer = NULL;
7373 rsurface.batchelement3s_bufferoffset = 0;
7374 rsurface.forcecurrenttextureupdate = false;
7377 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)
7379 rsurface.entity = r_refdef.scene.worldentity;
7380 rsurface.skeleton = NULL;
7381 rsurface.ent_skinnum = 0;
7382 rsurface.ent_qwskin = -1;
7383 rsurface.ent_flags = entflags;
7384 rsurface.shadertime = r_refdef.scene.time - shadertime;
7385 rsurface.modelnumvertices = numvertices;
7386 rsurface.modelnumtriangles = numtriangles;
7387 rsurface.matrix = *matrix;
7388 rsurface.inversematrix = *inversematrix;
7389 rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7390 rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7391 R_EntityMatrix(&rsurface.matrix);
7392 Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7393 Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7394 rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7395 rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7396 rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7397 rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7398 memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7399 rsurface.frameblend[0].lerp = 1;
7400 rsurface.ent_alttextures = false;
7401 rsurface.basepolygonfactor = r_refdef.polygonfactor;
7402 rsurface.basepolygonoffset = r_refdef.polygonoffset;
7403 rsurface.entityskeletaltransform3x4 = NULL;
7404 rsurface.entityskeletaltransform3x4buffer = NULL;
7405 rsurface.entityskeletaltransform3x4offset = 0;
7406 rsurface.entityskeletaltransform3x4size = 0;
7407 rsurface.entityskeletalnumtransforms = 0;
7408 r_refdef.stats[r_stat_batch_entitycustom_count]++;
7409 r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7410 r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7411 r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7414 rsurface.modelvertex3f = (float *)vertex3f;
7415 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7416 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7417 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7419 else if (wantnormals)
7421 rsurface.modelvertex3f = (float *)vertex3f;
7422 rsurface.modelsvector3f = NULL;
7423 rsurface.modeltvector3f = NULL;
7424 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7428 rsurface.modelvertex3f = (float *)vertex3f;
7429 rsurface.modelsvector3f = NULL;
7430 rsurface.modeltvector3f = NULL;
7431 rsurface.modelnormal3f = NULL;
7433 rsurface.modelvertexmesh = NULL;
7434 rsurface.modelvertexmesh_vertexbuffer = NULL;
7435 rsurface.modelvertexmesh_bufferoffset = 0;
7436 rsurface.modelvertex3f_vertexbuffer = 0;
7437 rsurface.modelvertex3f_bufferoffset = 0;
7438 rsurface.modelsvector3f_vertexbuffer = 0;
7439 rsurface.modelsvector3f_bufferoffset = 0;
7440 rsurface.modeltvector3f_vertexbuffer = 0;
7441 rsurface.modeltvector3f_bufferoffset = 0;
7442 rsurface.modelnormal3f_vertexbuffer = 0;
7443 rsurface.modelnormal3f_bufferoffset = 0;
7444 rsurface.modelgeneratedvertex = true;
7445 rsurface.modellightmapcolor4f = (float *)color4f;
7446 rsurface.modellightmapcolor4f_vertexbuffer = 0;
7447 rsurface.modellightmapcolor4f_bufferoffset = 0;
7448 rsurface.modeltexcoordtexture2f = (float *)texcoord2f;
7449 rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7450 rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7451 rsurface.modeltexcoordlightmap2f = NULL;
7452 rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7453 rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7454 rsurface.modelskeletalindex4ub = NULL;
7455 rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7456 rsurface.modelskeletalindex4ub_bufferoffset = 0;
7457 rsurface.modelskeletalweight4ub = NULL;
7458 rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7459 rsurface.modelskeletalweight4ub_bufferoffset = 0;
7460 rsurface.modelelement3i = (int *)element3i;
7461 rsurface.modelelement3i_indexbuffer = NULL;
7462 rsurface.modelelement3i_bufferoffset = 0;
7463 rsurface.modelelement3s = (unsigned short *)element3s;
7464 rsurface.modelelement3s_indexbuffer = NULL;
7465 rsurface.modelelement3s_bufferoffset = 0;
7466 rsurface.modellightmapoffsets = NULL;
7467 rsurface.modelsurfaces = NULL;
7468 rsurface.batchgeneratedvertex = false;
7469 rsurface.batchfirstvertex = 0;
7470 rsurface.batchnumvertices = 0;
7471 rsurface.batchfirsttriangle = 0;
7472 rsurface.batchnumtriangles = 0;
7473 rsurface.batchvertex3f = NULL;
7474 rsurface.batchvertex3f_vertexbuffer = NULL;
7475 rsurface.batchvertex3f_bufferoffset = 0;
7476 rsurface.batchsvector3f = NULL;
7477 rsurface.batchsvector3f_vertexbuffer = NULL;
7478 rsurface.batchsvector3f_bufferoffset = 0;
7479 rsurface.batchtvector3f = NULL;
7480 rsurface.batchtvector3f_vertexbuffer = NULL;
7481 rsurface.batchtvector3f_bufferoffset = 0;
7482 rsurface.batchnormal3f = NULL;
7483 rsurface.batchnormal3f_vertexbuffer = NULL;
7484 rsurface.batchnormal3f_bufferoffset = 0;
7485 rsurface.batchlightmapcolor4f = NULL;
7486 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7487 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7488 rsurface.batchtexcoordtexture2f = NULL;
7489 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7490 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7491 rsurface.batchtexcoordlightmap2f = NULL;
7492 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7493 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7494 rsurface.batchskeletalindex4ub = NULL;
7495 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7496 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7497 rsurface.batchskeletalweight4ub = NULL;
7498 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7499 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7500 rsurface.batchvertexmesh = NULL;
7501 rsurface.batchvertexmesh_vertexbuffer = NULL;
7502 rsurface.batchvertexmesh_bufferoffset = 0;
7503 rsurface.batchelement3i = NULL;
7504 rsurface.batchelement3i_indexbuffer = NULL;
7505 rsurface.batchelement3i_bufferoffset = 0;
7506 rsurface.batchelement3s = NULL;
7507 rsurface.batchelement3s_indexbuffer = NULL;
7508 rsurface.batchelement3s_bufferoffset = 0;
7509 rsurface.forcecurrenttextureupdate = true;
7511 if (rsurface.modelnumvertices && rsurface.modelelement3i)
7513 if ((wantnormals || wanttangents) && !normal3f)
7515 rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7516 Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7518 if (wanttangents && !svector3f)
7520 rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7521 rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7522 Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7527 float RSurf_FogPoint(const float *v)
7529 // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7530 float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7531 float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7532 float FogHeightFade = r_refdef.fogheightfade;
7534 unsigned int fogmasktableindex;
7535 if (r_refdef.fogplaneviewabove)
7536 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7538 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7539 fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7540 return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7543 float RSurf_FogVertex(const float *v)
7545 // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7546 float FogPlaneViewDist = rsurface.fogplaneviewdist;
7547 float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7548 float FogHeightFade = rsurface.fogheightfade;
7550 unsigned int fogmasktableindex;
7551 if (r_refdef.fogplaneviewabove)
7552 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7554 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7555 fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7556 return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7559 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7562 for (i = 0;i < numelements;i++)
7563 outelement3i[i] = inelement3i[i] + adjust;
7566 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7567 extern cvar_t gl_vbo;
7568 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7576 int surfacefirsttriangle;
7577 int surfacenumtriangles;
7578 int surfacefirstvertex;
7579 int surfaceendvertex;
7580 int surfacenumvertices;
7581 int batchnumsurfaces = texturenumsurfaces;
7582 int batchnumvertices;
7583 int batchnumtriangles;
7587 qboolean dynamicvertex;
7590 float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7593 q3shaderinfo_deform_t *deform;
7594 const msurface_t *surface, *firstsurface;
7595 r_vertexmesh_t *vertexmesh;
7596 if (!texturenumsurfaces)
7598 // find vertex range of this surface batch
7600 firstsurface = texturesurfacelist[0];
7601 firsttriangle = firstsurface->num_firsttriangle;
7602 batchnumvertices = 0;
7603 batchnumtriangles = 0;
7604 firstvertex = endvertex = firstsurface->num_firstvertex;
7605 for (i = 0;i < texturenumsurfaces;i++)
7607 surface = texturesurfacelist[i];
7608 if (surface != firstsurface + i)
7610 surfacefirstvertex = surface->num_firstvertex;
7611 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7612 surfacenumvertices = surface->num_vertices;
7613 surfacenumtriangles = surface->num_triangles;
7614 if (firstvertex > surfacefirstvertex)
7615 firstvertex = surfacefirstvertex;
7616 if (endvertex < surfaceendvertex)
7617 endvertex = surfaceendvertex;
7618 batchnumvertices += surfacenumvertices;
7619 batchnumtriangles += surfacenumtriangles;
7622 r_refdef.stats[r_stat_batch_batches]++;
7624 r_refdef.stats[r_stat_batch_withgaps]++;
7625 r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7626 r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7627 r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7629 // we now know the vertex range used, and if there are any gaps in it
7630 rsurface.batchfirstvertex = firstvertex;
7631 rsurface.batchnumvertices = endvertex - firstvertex;
7632 rsurface.batchfirsttriangle = firsttriangle;
7633 rsurface.batchnumtriangles = batchnumtriangles;
7635 // this variable holds flags for which properties have been updated that
7636 // may require regenerating vertexmesh array...
7639 // check if any dynamic vertex processing must occur
7640 dynamicvertex = false;
7642 // a cvar to force the dynamic vertex path to be taken, for debugging
7643 if (r_batch_debugdynamicvertexpath.integer)
7647 r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7648 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7649 r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7650 r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7652 dynamicvertex = true;
7655 // if there is a chance of animated vertex colors, it's a dynamic batch
7656 if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo)
7660 r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7661 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7662 r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7663 r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7665 dynamicvertex = true;
7666 needsupdate |= BATCHNEED_VERTEXMESH_VERTEXCOLOR;
7669 for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7671 switch (deform->deform)
7674 case Q3DEFORM_PROJECTIONSHADOW:
7675 case Q3DEFORM_TEXT0:
7676 case Q3DEFORM_TEXT1:
7677 case Q3DEFORM_TEXT2:
7678 case Q3DEFORM_TEXT3:
7679 case Q3DEFORM_TEXT4:
7680 case Q3DEFORM_TEXT5:
7681 case Q3DEFORM_TEXT6:
7682 case Q3DEFORM_TEXT7:
7685 case Q3DEFORM_AUTOSPRITE:
7688 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7689 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7690 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7691 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7693 dynamicvertex = true;
7694 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7695 needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7697 case Q3DEFORM_AUTOSPRITE2:
7700 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7701 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7702 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7703 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7705 dynamicvertex = true;
7706 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7707 needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7709 case Q3DEFORM_NORMAL:
7712 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7713 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7714 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7715 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7717 dynamicvertex = true;
7718 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7719 needsupdate |= BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7722 if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7723 break; // if wavefunc is a nop, ignore this transform
7726 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7727 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7728 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7729 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7731 dynamicvertex = true;
7732 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7733 needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7735 case Q3DEFORM_BULGE:
7738 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7739 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7740 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7741 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7743 dynamicvertex = true;
7744 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7745 needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7748 if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7749 break; // if wavefunc is a nop, ignore this transform
7752 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7753 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7754 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7755 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7757 dynamicvertex = true;
7758 batchneed |= BATCHNEED_ARRAY_VERTEX;
7759 needsupdate |= BATCHNEED_VERTEXMESH_VERTEX;
7763 if (rsurface.texture->materialshaderpass)
7765 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7768 case Q3TCGEN_TEXTURE:
7770 case Q3TCGEN_LIGHTMAP:
7773 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7774 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7775 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7776 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7778 dynamicvertex = true;
7779 batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7780 needsupdate |= BATCHNEED_VERTEXMESH_LIGHTMAP;
7782 case Q3TCGEN_VECTOR:
7785 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7786 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7787 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7788 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7790 dynamicvertex = true;
7791 batchneed |= BATCHNEED_ARRAY_VERTEX;
7792 needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
7794 case Q3TCGEN_ENVIRONMENT:
7797 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7798 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7799 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7800 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7802 dynamicvertex = true;
7803 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7804 needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
7807 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7811 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7812 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7813 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7814 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7816 dynamicvertex = true;
7817 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7818 needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
7822 if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)))
7826 r_refdef.stats[r_stat_batch_dynamic_batches_because_interleavedarrays] += 1;
7827 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_interleavedarrays] += batchnumsurfaces;
7828 r_refdef.stats[r_stat_batch_dynamic_vertices_because_interleavedarrays] += batchnumvertices;
7829 r_refdef.stats[r_stat_batch_dynamic_triangles_because_interleavedarrays] += batchnumtriangles;
7831 dynamicvertex = true;
7832 needsupdate |= (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP));
7835 // when the model data has no vertex buffer (dynamic mesh), we need to
7837 if (vid.useinterleavedarrays && !rsurface.modelvertexmesh_vertexbuffer)
7838 batchneed |= BATCHNEED_NOGAPS;
7840 // the caller can specify BATCHNEED_NOGAPS to force a batch with
7841 // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7842 // we ensure this by treating the vertex batch as dynamic...
7843 if ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0))
7847 r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7848 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7849 r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7850 r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7852 dynamicvertex = true;
7857 // when copying, we need to consider the regeneration of vertexmesh, any dependencies it may have must be set...
7858 if (batchneed & BATCHNEED_VERTEXMESH_VERTEX) batchneed |= BATCHNEED_ARRAY_VERTEX;
7859 if (batchneed & BATCHNEED_VERTEXMESH_NORMAL) batchneed |= BATCHNEED_ARRAY_NORMAL;
7860 if (batchneed & BATCHNEED_VERTEXMESH_VECTOR) batchneed |= BATCHNEED_ARRAY_VECTOR;
7861 if (batchneed & BATCHNEED_VERTEXMESH_VERTEXCOLOR) batchneed |= BATCHNEED_ARRAY_VERTEXCOLOR;
7862 if (batchneed & BATCHNEED_VERTEXMESH_TEXCOORD) batchneed |= BATCHNEED_ARRAY_TEXCOORD;
7863 if (batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP) batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7864 if (batchneed & BATCHNEED_VERTEXMESH_SKELETAL) batchneed |= BATCHNEED_ARRAY_SKELETAL;
7867 // if needsupdate, we have to do a dynamic vertex batch for sure
7868 if (needsupdate & batchneed)
7872 r_refdef.stats[r_stat_batch_dynamic_batches_because_derived] += 1;
7873 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_derived] += batchnumsurfaces;
7874 r_refdef.stats[r_stat_batch_dynamic_vertices_because_derived] += batchnumvertices;
7875 r_refdef.stats[r_stat_batch_dynamic_triangles_because_derived] += batchnumtriangles;
7877 dynamicvertex = true;
7880 // see if we need to build vertexmesh from arrays
7881 if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)))
7885 r_refdef.stats[r_stat_batch_dynamic_batches_because_interleavedarrays] += 1;
7886 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_interleavedarrays] += batchnumsurfaces;
7887 r_refdef.stats[r_stat_batch_dynamic_vertices_because_interleavedarrays] += batchnumvertices;
7888 r_refdef.stats[r_stat_batch_dynamic_triangles_because_interleavedarrays] += batchnumtriangles;
7890 dynamicvertex = true;
7893 // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7894 if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7895 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7897 rsurface.batchvertex3f = rsurface.modelvertex3f;
7898 rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7899 rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7900 rsurface.batchsvector3f = rsurface.modelsvector3f;
7901 rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7902 rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7903 rsurface.batchtvector3f = rsurface.modeltvector3f;
7904 rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7905 rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7906 rsurface.batchnormal3f = rsurface.modelnormal3f;
7907 rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7908 rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7909 rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7910 rsurface.batchlightmapcolor4f_vertexbuffer = rsurface.modellightmapcolor4f_vertexbuffer;
7911 rsurface.batchlightmapcolor4f_bufferoffset = rsurface.modellightmapcolor4f_bufferoffset;
7912 rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7913 rsurface.batchtexcoordtexture2f_vertexbuffer = rsurface.modeltexcoordtexture2f_vertexbuffer;
7914 rsurface.batchtexcoordtexture2f_bufferoffset = rsurface.modeltexcoordtexture2f_bufferoffset;
7915 rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7916 rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7917 rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7918 rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7919 rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7920 rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7921 rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7922 rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7923 rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7924 rsurface.batchvertexmesh = rsurface.modelvertexmesh;
7925 rsurface.batchvertexmesh_vertexbuffer = rsurface.modelvertexmesh_vertexbuffer;
7926 rsurface.batchvertexmesh_bufferoffset = rsurface.modelvertexmesh_bufferoffset;
7927 rsurface.batchelement3i = rsurface.modelelement3i;
7928 rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7929 rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7930 rsurface.batchelement3s = rsurface.modelelement3s;
7931 rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7932 rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7933 rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7934 rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7935 rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7936 rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7937 rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7939 // if any dynamic vertex processing has to occur in software, we copy the
7940 // entire surface list together before processing to rebase the vertices
7941 // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7943 // if any gaps exist and we do not have a static vertex buffer, we have to
7944 // copy the surface list together to avoid wasting upload bandwidth on the
7945 // vertices in the gaps.
7947 // if gaps exist and we have a static vertex buffer, we can choose whether
7948 // to combine the index buffer ranges into one dynamic index buffer or
7949 // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7951 // in many cases the batch is reduced to one draw call.
7953 rsurface.batchmultidraw = false;
7954 rsurface.batchmultidrawnumsurfaces = 0;
7955 rsurface.batchmultidrawsurfacelist = NULL;
7959 // static vertex data, just set pointers...
7960 rsurface.batchgeneratedvertex = false;
7961 // if there are gaps, we want to build a combined index buffer,
7962 // otherwise use the original static buffer with an appropriate offset
7965 r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7966 r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7967 r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7968 r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7969 if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7971 rsurface.batchmultidraw = true;
7972 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7973 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7976 // build a new triangle elements array for this batch
7977 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7978 rsurface.batchfirsttriangle = 0;
7980 for (i = 0;i < texturenumsurfaces;i++)
7982 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7983 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7984 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7985 numtriangles += surfacenumtriangles;
7987 rsurface.batchelement3i_indexbuffer = NULL;
7988 rsurface.batchelement3i_bufferoffset = 0;
7989 rsurface.batchelement3s = NULL;
7990 rsurface.batchelement3s_indexbuffer = NULL;
7991 rsurface.batchelement3s_bufferoffset = 0;
7992 if (endvertex <= 65536)
7994 // make a 16bit (unsigned short) index array if possible
7995 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7996 for (i = 0;i < numtriangles*3;i++)
7997 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7999 // upload buffer data for the copytriangles batch
8000 if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo)
8002 if (rsurface.batchelement3s)
8003 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
8004 else if (rsurface.batchelement3i)
8005 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
8010 r_refdef.stats[r_stat_batch_fast_batches] += 1;
8011 r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
8012 r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
8013 r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
8018 // something needs software processing, do it for real...
8019 // we only directly handle separate array data in this case and then
8020 // generate interleaved data if needed...
8021 rsurface.batchgeneratedvertex = true;
8022 r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
8023 r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
8024 r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
8025 r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
8027 // now copy the vertex data into a combined array and make an index array
8028 // (this is what Quake3 does all the time)
8029 // we also apply any skeletal animation here that would have been done in
8030 // the vertex shader, because most of the dynamic vertex animation cases
8031 // need actual vertex positions and normals
8032 //if (dynamicvertex)
8034 rsurface.batchvertexmesh = NULL;
8035 rsurface.batchvertexmesh_vertexbuffer = NULL;
8036 rsurface.batchvertexmesh_bufferoffset = 0;
8037 rsurface.batchvertex3f = NULL;
8038 rsurface.batchvertex3f_vertexbuffer = NULL;
8039 rsurface.batchvertex3f_bufferoffset = 0;
8040 rsurface.batchsvector3f = NULL;
8041 rsurface.batchsvector3f_vertexbuffer = NULL;
8042 rsurface.batchsvector3f_bufferoffset = 0;
8043 rsurface.batchtvector3f = NULL;
8044 rsurface.batchtvector3f_vertexbuffer = NULL;
8045 rsurface.batchtvector3f_bufferoffset = 0;
8046 rsurface.batchnormal3f = NULL;
8047 rsurface.batchnormal3f_vertexbuffer = NULL;
8048 rsurface.batchnormal3f_bufferoffset = 0;
8049 rsurface.batchlightmapcolor4f = NULL;
8050 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8051 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8052 rsurface.batchtexcoordtexture2f = NULL;
8053 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8054 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8055 rsurface.batchtexcoordlightmap2f = NULL;
8056 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
8057 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
8058 rsurface.batchskeletalindex4ub = NULL;
8059 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
8060 rsurface.batchskeletalindex4ub_bufferoffset = 0;
8061 rsurface.batchskeletalweight4ub = NULL;
8062 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
8063 rsurface.batchskeletalweight4ub_bufferoffset = 0;
8064 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
8065 rsurface.batchelement3i_indexbuffer = NULL;
8066 rsurface.batchelement3i_bufferoffset = 0;
8067 rsurface.batchelement3s = NULL;
8068 rsurface.batchelement3s_indexbuffer = NULL;
8069 rsurface.batchelement3s_bufferoffset = 0;
8070 rsurface.batchskeletaltransform3x4buffer = NULL;
8071 rsurface.batchskeletaltransform3x4offset = 0;
8072 rsurface.batchskeletaltransform3x4size = 0;
8073 // we'll only be setting up certain arrays as needed
8074 if (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP))
8075 rsurface.batchvertexmesh = (r_vertexmesh_t *)R_FrameData_Alloc(batchnumvertices * sizeof(r_vertexmesh_t));
8076 if (batchneed & BATCHNEED_ARRAY_VERTEX)
8077 rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8078 if (batchneed & BATCHNEED_ARRAY_NORMAL)
8079 rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8080 if (batchneed & BATCHNEED_ARRAY_VECTOR)
8082 rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8083 rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8085 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
8086 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8087 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
8088 rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8089 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
8090 rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8091 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
8093 rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
8094 rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
8098 for (i = 0;i < texturenumsurfaces;i++)
8100 surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
8101 surfacenumvertices = texturesurfacelist[i]->num_vertices;
8102 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
8103 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
8104 // copy only the data requested
8105 if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)) && rsurface.modelvertexmesh)
8106 memcpy(rsurface.batchvertexmesh + numvertices, rsurface.modelvertexmesh + surfacefirstvertex, surfacenumvertices * sizeof(rsurface.batchvertexmesh[0]));
8107 if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
8109 if (batchneed & BATCHNEED_ARRAY_VERTEX)
8111 if (rsurface.batchvertex3f)
8112 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8114 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8116 if (batchneed & BATCHNEED_ARRAY_NORMAL)
8118 if (rsurface.modelnormal3f)
8119 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8121 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8123 if (batchneed & BATCHNEED_ARRAY_VECTOR)
8125 if (rsurface.modelsvector3f)
8127 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8128 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8132 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8133 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8136 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
8138 if (rsurface.modellightmapcolor4f)
8139 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
8141 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
8143 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
8145 if (rsurface.modeltexcoordtexture2f)
8146 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
8148 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
8150 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
8152 if (rsurface.modeltexcoordlightmap2f)
8153 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
8155 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
8157 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
8159 if (rsurface.modelskeletalindex4ub)
8161 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
8162 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
8166 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
8167 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
8168 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
8169 for (j = 0;j < surfacenumvertices;j++)
8174 RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
8175 numvertices += surfacenumvertices;
8176 numtriangles += surfacenumtriangles;
8179 // generate a 16bit index array as well if possible
8180 // (in general, dynamic batches fit)
8181 if (numvertices <= 65536)
8183 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
8184 for (i = 0;i < numtriangles*3;i++)
8185 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
8188 // since we've copied everything, the batch now starts at 0
8189 rsurface.batchfirstvertex = 0;
8190 rsurface.batchnumvertices = batchnumvertices;
8191 rsurface.batchfirsttriangle = 0;
8192 rsurface.batchnumtriangles = batchnumtriangles;
8195 // apply skeletal animation that would have been done in the vertex shader
8196 if (rsurface.batchskeletaltransform3x4)
8198 const unsigned char *si;
8199 const unsigned char *sw;
8201 const float *b = rsurface.batchskeletaltransform3x4;
8202 float *vp, *vs, *vt, *vn;
8204 float m[3][4], n[3][4];
8205 float tp[3], ts[3], tt[3], tn[3];
8206 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
8207 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
8208 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
8209 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
8210 si = rsurface.batchskeletalindex4ub;
8211 sw = rsurface.batchskeletalweight4ub;
8212 vp = rsurface.batchvertex3f;
8213 vs = rsurface.batchsvector3f;
8214 vt = rsurface.batchtvector3f;
8215 vn = rsurface.batchnormal3f;
8216 memset(m[0], 0, sizeof(m));
8217 memset(n[0], 0, sizeof(n));
8218 for (i = 0;i < batchnumvertices;i++)
8220 t[0] = b + si[0]*12;
8223 // common case - only one matrix
8237 else if (sw[2] + sw[3])
8240 t[1] = b + si[1]*12;
8241 t[2] = b + si[2]*12;
8242 t[3] = b + si[3]*12;
8243 w[0] = sw[0] * (1.0f / 255.0f);
8244 w[1] = sw[1] * (1.0f / 255.0f);
8245 w[2] = sw[2] * (1.0f / 255.0f);
8246 w[3] = sw[3] * (1.0f / 255.0f);
8247 // blend the matrices
8248 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
8249 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
8250 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
8251 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
8252 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
8253 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
8254 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
8255 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
8256 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
8257 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
8258 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
8259 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
8264 t[1] = b + si[1]*12;
8265 w[0] = sw[0] * (1.0f / 255.0f);
8266 w[1] = sw[1] * (1.0f / 255.0f);
8267 // blend the matrices
8268 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
8269 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
8270 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
8271 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
8272 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
8273 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
8274 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
8275 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
8276 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
8277 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
8278 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
8279 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
8283 // modify the vertex
8285 vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
8286 vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
8287 vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
8291 // the normal transformation matrix is a set of cross products...
8292 CrossProduct(m[1], m[2], n[0]);
8293 CrossProduct(m[2], m[0], n[1]);
8294 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8296 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8297 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8298 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8299 VectorNormalize(vn);
8304 vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8305 vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8306 vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8307 VectorNormalize(vs);
8310 vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8311 vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8312 vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8313 VectorNormalize(vt);
8318 rsurface.batchskeletaltransform3x4 = NULL;
8319 rsurface.batchskeletalnumtransforms = 0;
8322 // q1bsp surfaces rendered in vertex color mode have to have colors
8323 // calculated based on lightstyles
8324 if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo)
8326 // generate color arrays for the surfaces in this list
8331 const unsigned char *lm;
8332 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8333 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8334 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8336 for (i = 0;i < texturenumsurfaces;i++)
8338 surface = texturesurfacelist[i];
8339 offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8340 surfacenumvertices = surface->num_vertices;
8341 if (surface->lightmapinfo->samples)
8343 for (j = 0;j < surfacenumvertices;j++)
8345 lm = surface->lightmapinfo->samples + offsets[j];
8346 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8347 VectorScale(lm, scale, c);
8348 if (surface->lightmapinfo->styles[1] != 255)
8350 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8352 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8353 VectorMA(c, scale, lm, c);
8354 if (surface->lightmapinfo->styles[2] != 255)
8357 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8358 VectorMA(c, scale, lm, c);
8359 if (surface->lightmapinfo->styles[3] != 255)
8362 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8363 VectorMA(c, scale, lm, c);
8370 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);
8376 for (j = 0;j < surfacenumvertices;j++)
8378 Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8385 // if vertices are deformed (sprite flares and things in maps, possibly
8386 // water waves, bulges and other deformations), modify the copied vertices
8388 for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8391 switch (deform->deform)
8394 case Q3DEFORM_PROJECTIONSHADOW:
8395 case Q3DEFORM_TEXT0:
8396 case Q3DEFORM_TEXT1:
8397 case Q3DEFORM_TEXT2:
8398 case Q3DEFORM_TEXT3:
8399 case Q3DEFORM_TEXT4:
8400 case Q3DEFORM_TEXT5:
8401 case Q3DEFORM_TEXT6:
8402 case Q3DEFORM_TEXT7:
8405 case Q3DEFORM_AUTOSPRITE:
8406 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8407 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8408 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8409 VectorNormalize(newforward);
8410 VectorNormalize(newright);
8411 VectorNormalize(newup);
8412 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8413 // rsurface.batchvertex3f_vertexbuffer = NULL;
8414 // rsurface.batchvertex3f_bufferoffset = 0;
8415 // rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8416 // rsurface.batchsvector3f_vertexbuffer = NULL;
8417 // rsurface.batchsvector3f_bufferoffset = 0;
8418 // rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8419 // rsurface.batchtvector3f_vertexbuffer = NULL;
8420 // rsurface.batchtvector3f_bufferoffset = 0;
8421 // rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8422 // rsurface.batchnormal3f_vertexbuffer = NULL;
8423 // rsurface.batchnormal3f_bufferoffset = 0;
8424 // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8425 if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8426 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8427 if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8428 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);
8429 // a single autosprite surface can contain multiple sprites...
8430 for (j = 0;j < batchnumvertices - 3;j += 4)
8432 VectorClear(center);
8433 for (i = 0;i < 4;i++)
8434 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8435 VectorScale(center, 0.25f, center);
8436 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8437 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8438 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8439 for (i = 0;i < 4;i++)
8441 VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8442 VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8445 // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8446 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8447 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);
8449 case Q3DEFORM_AUTOSPRITE2:
8450 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8451 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8452 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8453 VectorNormalize(newforward);
8454 VectorNormalize(newright);
8455 VectorNormalize(newup);
8456 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8457 // rsurface.batchvertex3f_vertexbuffer = NULL;
8458 // rsurface.batchvertex3f_bufferoffset = 0;
8460 const float *v1, *v2;
8470 memset(shortest, 0, sizeof(shortest));
8471 // a single autosprite surface can contain multiple sprites...
8472 for (j = 0;j < batchnumvertices - 3;j += 4)
8474 VectorClear(center);
8475 for (i = 0;i < 4;i++)
8476 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8477 VectorScale(center, 0.25f, center);
8478 // find the two shortest edges, then use them to define the
8479 // axis vectors for rotating around the central axis
8480 for (i = 0;i < 6;i++)
8482 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8483 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8484 l = VectorDistance2(v1, v2);
8485 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8487 l += (1.0f / 1024.0f);
8488 if (shortest[0].length2 > l || i == 0)
8490 shortest[1] = shortest[0];
8491 shortest[0].length2 = l;
8492 shortest[0].v1 = v1;
8493 shortest[0].v2 = v2;
8495 else if (shortest[1].length2 > l || i == 1)
8497 shortest[1].length2 = l;
8498 shortest[1].v1 = v1;
8499 shortest[1].v2 = v2;
8502 VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8503 VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8504 // this calculates the right vector from the shortest edge
8505 // and the up vector from the edge midpoints
8506 VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8507 VectorNormalize(right);
8508 VectorSubtract(end, start, up);
8509 VectorNormalize(up);
8510 // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8511 VectorSubtract(rsurface.localvieworigin, center, forward);
8512 //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8513 VectorNegate(forward, forward);
8514 VectorReflect(forward, 0, up, forward);
8515 VectorNormalize(forward);
8516 CrossProduct(up, forward, newright);
8517 VectorNormalize(newright);
8518 // rotate the quad around the up axis vector, this is made
8519 // especially easy by the fact we know the quad is flat,
8520 // so we only have to subtract the center position and
8521 // measure distance along the right vector, and then
8522 // multiply that by the newright vector and add back the
8524 // we also need to subtract the old position to undo the
8525 // displacement from the center, which we do with a
8526 // DotProduct, the subtraction/addition of center is also
8527 // optimized into DotProducts here
8528 l = DotProduct(right, center);
8529 for (i = 0;i < 4;i++)
8531 v1 = rsurface.batchvertex3f + 3*(j+i);
8532 f = DotProduct(right, v1) - l;
8533 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8537 if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8539 // rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8540 // rsurface.batchnormal3f_vertexbuffer = NULL;
8541 // rsurface.batchnormal3f_bufferoffset = 0;
8542 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8544 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8546 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8547 // rsurface.batchsvector3f_vertexbuffer = NULL;
8548 // rsurface.batchsvector3f_bufferoffset = 0;
8549 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8550 // rsurface.batchtvector3f_vertexbuffer = NULL;
8551 // rsurface.batchtvector3f_bufferoffset = 0;
8552 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);
8555 case Q3DEFORM_NORMAL:
8556 // deform the normals to make reflections wavey
8557 rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8558 rsurface.batchnormal3f_vertexbuffer = NULL;
8559 rsurface.batchnormal3f_bufferoffset = 0;
8560 for (j = 0;j < batchnumvertices;j++)
8563 float *normal = rsurface.batchnormal3f + 3*j;
8564 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8565 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f( vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8566 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8567 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8568 VectorNormalize(normal);
8570 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8572 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8573 // rsurface.batchsvector3f_vertexbuffer = NULL;
8574 // rsurface.batchsvector3f_bufferoffset = 0;
8575 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8576 // rsurface.batchtvector3f_vertexbuffer = NULL;
8577 // rsurface.batchtvector3f_bufferoffset = 0;
8578 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);
8582 // deform vertex array to make wavey water and flags and such
8583 waveparms[0] = deform->waveparms[0];
8584 waveparms[1] = deform->waveparms[1];
8585 waveparms[2] = deform->waveparms[2];
8586 waveparms[3] = deform->waveparms[3];
8587 if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8588 break; // if wavefunc is a nop, don't make a dynamic vertex array
8589 // this is how a divisor of vertex influence on deformation
8590 animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8591 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8592 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8593 // rsurface.batchvertex3f_vertexbuffer = NULL;
8594 // rsurface.batchvertex3f_bufferoffset = 0;
8595 // rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8596 // rsurface.batchnormal3f_vertexbuffer = NULL;
8597 // rsurface.batchnormal3f_bufferoffset = 0;
8598 for (j = 0;j < batchnumvertices;j++)
8600 // if the wavefunc depends on time, evaluate it per-vertex
8603 waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8604 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8606 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8608 // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8609 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8610 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8612 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8613 // rsurface.batchsvector3f_vertexbuffer = NULL;
8614 // rsurface.batchsvector3f_bufferoffset = 0;
8615 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8616 // rsurface.batchtvector3f_vertexbuffer = NULL;
8617 // rsurface.batchtvector3f_bufferoffset = 0;
8618 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);
8621 case Q3DEFORM_BULGE:
8622 // deform vertex array to make the surface have moving bulges
8623 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8624 // rsurface.batchvertex3f_vertexbuffer = NULL;
8625 // rsurface.batchvertex3f_bufferoffset = 0;
8626 // rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8627 // rsurface.batchnormal3f_vertexbuffer = NULL;
8628 // rsurface.batchnormal3f_bufferoffset = 0;
8629 for (j = 0;j < batchnumvertices;j++)
8631 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8632 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8634 // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8635 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8636 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8638 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8639 // rsurface.batchsvector3f_vertexbuffer = NULL;
8640 // rsurface.batchsvector3f_bufferoffset = 0;
8641 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8642 // rsurface.batchtvector3f_vertexbuffer = NULL;
8643 // rsurface.batchtvector3f_bufferoffset = 0;
8644 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);
8648 // deform vertex array
8649 if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8650 break; // if wavefunc is a nop, don't make a dynamic vertex array
8651 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8652 VectorScale(deform->parms, scale, waveparms);
8653 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8654 // rsurface.batchvertex3f_vertexbuffer = NULL;
8655 // rsurface.batchvertex3f_bufferoffset = 0;
8656 for (j = 0;j < batchnumvertices;j++)
8657 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8662 if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8664 // generate texcoords based on the chosen texcoord source
8665 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8668 case Q3TCGEN_TEXTURE:
8670 case Q3TCGEN_LIGHTMAP:
8671 // rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8672 // rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8673 // rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8674 if (rsurface.batchtexcoordlightmap2f)
8675 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8677 case Q3TCGEN_VECTOR:
8678 // rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8679 // rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8680 // rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8681 for (j = 0;j < batchnumvertices;j++)
8683 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8684 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8687 case Q3TCGEN_ENVIRONMENT:
8688 // make environment reflections using a spheremap
8689 rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8690 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8691 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8692 for (j = 0;j < batchnumvertices;j++)
8694 // identical to Q3A's method, but executed in worldspace so
8695 // carried models can be shiny too
8697 float viewer[3], d, reflected[3], worldreflected[3];
8699 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8700 // VectorNormalize(viewer);
8702 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8704 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8705 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8706 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8707 // note: this is proportinal to viewer, so we can normalize later
8709 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8710 VectorNormalize(worldreflected);
8712 // note: this sphere map only uses world x and z!
8713 // so positive and negative y will LOOK THE SAME.
8714 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8715 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8719 // the only tcmod that needs software vertex processing is turbulent, so
8720 // check for it here and apply the changes if needed
8721 // and we only support that as the first one
8722 // (handling a mixture of turbulent and other tcmods would be problematic
8723 // without punting it entirely to a software path)
8724 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8726 amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8727 animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8728 // rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8729 // rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8730 // rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8731 for (j = 0;j < batchnumvertices;j++)
8733 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);
8734 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1] ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8739 if (needsupdate & batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP))
8741 // convert the modified arrays to vertex structs
8742 // rsurface.batchvertexmesh = R_FrameData_Alloc(batchnumvertices * sizeof(r_vertexmesh_t));
8743 // rsurface.batchvertexmesh_vertexbuffer = NULL;
8744 // rsurface.batchvertexmesh_bufferoffset = 0;
8745 if (batchneed & BATCHNEED_VERTEXMESH_VERTEX)
8746 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8747 VectorCopy(rsurface.batchvertex3f + 3*j, vertexmesh->vertex3f);
8748 if (batchneed & BATCHNEED_VERTEXMESH_NORMAL)
8749 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8750 VectorCopy(rsurface.batchnormal3f + 3*j, vertexmesh->normal3f);
8751 if (batchneed & BATCHNEED_VERTEXMESH_VECTOR)
8753 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8755 VectorCopy(rsurface.batchsvector3f + 3*j, vertexmesh->svector3f);
8756 VectorCopy(rsurface.batchtvector3f + 3*j, vertexmesh->tvector3f);
8759 if ((batchneed & BATCHNEED_VERTEXMESH_VERTEXCOLOR) && rsurface.batchlightmapcolor4f)
8760 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8761 Vector4Copy(rsurface.batchlightmapcolor4f + 4*j, vertexmesh->color4f);
8762 if (batchneed & BATCHNEED_VERTEXMESH_TEXCOORD)
8763 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8764 Vector2Copy(rsurface.batchtexcoordtexture2f + 2*j, vertexmesh->texcoordtexture2f);
8765 if ((batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP) && rsurface.batchtexcoordlightmap2f)
8766 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8767 Vector2Copy(rsurface.batchtexcoordlightmap2f + 2*j, vertexmesh->texcoordlightmap2f);
8768 if ((batchneed & BATCHNEED_VERTEXMESH_SKELETAL) && rsurface.batchskeletalindex4ub)
8770 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8772 Vector4Copy(rsurface.batchskeletalindex4ub + 4*j, vertexmesh->skeletalindex4ub);
8773 Vector4Copy(rsurface.batchskeletalweight4ub + 4*j, vertexmesh->skeletalweight4ub);
8778 // upload buffer data for the dynamic batch
8779 if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicvertex.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo)
8781 if (rsurface.batchvertexmesh)
8782 rsurface.batchvertexmesh_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(r_vertexmesh_t), rsurface.batchvertexmesh, R_BUFFERDATA_VERTEX, &rsurface.batchvertexmesh_bufferoffset);
8785 if (rsurface.batchvertex3f)
8786 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
8787 if (rsurface.batchsvector3f)
8788 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
8789 if (rsurface.batchtvector3f)
8790 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
8791 if (rsurface.batchnormal3f)
8792 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
8793 if (rsurface.batchlightmapcolor4f)
8794 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
8795 if (rsurface.batchtexcoordtexture2f)
8796 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
8797 if (rsurface.batchtexcoordlightmap2f)
8798 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
8799 if (rsurface.batchskeletalindex4ub)
8800 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
8801 if (rsurface.batchskeletalweight4ub)
8802 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
8804 if (rsurface.batchelement3s)
8805 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
8806 else if (rsurface.batchelement3i)
8807 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
8811 void RSurf_DrawBatch(void)
8813 // sometimes a zero triangle surface (usually a degenerate patch) makes it
8814 // through the pipeline, killing it earlier in the pipeline would have
8815 // per-surface overhead rather than per-batch overhead, so it's best to
8816 // reject it here, before it hits glDraw.
8817 if (rsurface.batchnumtriangles == 0)
8820 // batch debugging code
8821 if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8827 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8828 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8831 for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8833 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8835 if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8836 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);
8843 if (rsurface.batchmultidraw)
8845 // issue multiple draws rather than copying index data
8846 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8847 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8848 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8849 for (i = 0;i < numsurfaces;)
8851 // combine consecutive surfaces as one draw
8852 for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8853 if (surfacelist[j] != surfacelist[k] + 1)
8855 firstvertex = surfacelist[i]->num_firstvertex;
8856 endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8857 firsttriangle = surfacelist[i]->num_firsttriangle;
8858 endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8859 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);
8865 // there is only one consecutive run of index data (may have been combined)
8866 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);
8870 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8872 // pick the closest matching water plane
8873 int planeindex, vertexindex, bestplaneindex = -1;
8877 r_waterstate_waterplane_t *p;
8878 qboolean prepared = false;
8880 for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8882 if(p->camera_entity != rsurface.texture->camera_entity)
8887 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8889 if(rsurface.batchnumvertices == 0)
8892 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8894 Matrix4x4_Transform(&rsurface.matrix, v, vert);
8895 d += fabs(PlaneDiff(vert, &p->plane));
8897 if (bestd > d || bestplaneindex < 0)
8900 bestplaneindex = planeindex;
8903 return bestplaneindex;
8904 // NOTE: this MAY return a totally unrelated water plane; we can ignore
8905 // this situation though, as it might be better to render single larger
8906 // batches with useless stuff (backface culled for example) than to
8907 // render multiple smaller batches
8910 void RSurf_SetupDepthAndCulling(void)
8912 // submodels are biased to avoid z-fighting with world surfaces that they
8913 // may be exactly overlapping (avoids z-fighting artifacts on certain
8914 // doors and things in Quake maps)
8915 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8916 GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8917 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8918 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8921 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8924 // transparent sky would be ridiculous
8925 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8927 R_SetupShader_Generic_NoTexture(false, false);
8928 skyrenderlater = true;
8929 RSurf_SetupDepthAndCulling();
8932 // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8933 if (r_sky_scissor.integer)
8935 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8936 for (i = 0; i < texturenumsurfaces; i++)
8938 const msurface_t *surf = texturesurfacelist[i];
8941 float mins[3], maxs[3];
8943 for (j = 0, v = rsurface.batchvertex3f + 3 * surf->num_firstvertex; j < surf->num_vertices; j++, v += 3)
8945 Matrix4x4_Transform(&rsurface.matrix, v, p);
8948 if (mins[0] > p[0]) mins[0] = p[0];
8949 if (mins[1] > p[1]) mins[1] = p[1];
8950 if (mins[2] > p[2]) mins[2] = p[2];
8951 if (maxs[0] < p[0]) maxs[0] = p[0];
8952 if (maxs[1] < p[1]) maxs[1] = p[1];
8953 if (maxs[2] < p[2]) maxs[2] = p[2];
8957 VectorCopy(p, mins);
8958 VectorCopy(p, maxs);
8961 if (!R_ScissorForBBox(mins, maxs, scissor))
8965 if (skyscissor[0] > scissor[0])
8967 skyscissor[2] += skyscissor[0] - scissor[0];
8968 skyscissor[0] = scissor[0];
8970 if (skyscissor[1] > scissor[1])
8972 skyscissor[3] += skyscissor[1] - scissor[1];
8973 skyscissor[1] = scissor[1];
8975 if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8976 skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8977 if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8978 skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8981 Vector4Copy(scissor, skyscissor);
8986 // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8987 // skymasking on them, and Quake3 never did sky masking (unlike
8988 // software Quake and software Quake2), so disable the sky masking
8989 // in Quake3 maps as it causes problems with q3map2 sky tricks,
8990 // and skymasking also looks very bad when noclipping outside the
8991 // level, so don't use it then either.
8992 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)
8994 R_Mesh_ResetTextureState();
8995 if (skyrendermasked)
8997 R_SetupShader_DepthOrShadow(false, false, false);
8998 // depth-only (masking)
8999 GL_ColorMask(0, 0, 0, 0);
9000 // just to make sure that braindead drivers don't draw
9001 // anything despite that colormask...
9002 GL_BlendFunc(GL_ZERO, GL_ONE);
9003 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9004 R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9008 R_SetupShader_Generic_NoTexture(false, false);
9010 GL_BlendFunc(GL_ONE, GL_ZERO);
9011 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9012 GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
9013 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9016 if (skyrendermasked)
9017 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
9019 R_Mesh_ResetTextureState();
9020 GL_Color(1, 1, 1, 1);
9023 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
9024 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
9025 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
9027 if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
9031 // render screenspace normalmap to texture
9033 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false);
9038 // bind lightmap texture
9040 // water/refraction/reflection/camera surfaces have to be handled specially
9041 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
9043 int start, end, startplaneindex;
9044 for (start = 0;start < texturenumsurfaces;start = end)
9046 startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
9047 if(startplaneindex < 0)
9049 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
9050 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
9054 for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
9056 // now that we have a batch using the same planeindex, render it
9057 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
9059 // render water or distortion background
9061 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
9063 // blend surface on top
9064 GL_DepthMask(false);
9065 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false);
9068 else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
9070 // render surface with reflection texture as input
9071 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
9072 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
9079 // render surface batch normally
9080 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
9081 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0);
9085 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
9089 r_vertexgeneric_t *batchvertex;
9091 texture_t *t = rsurface.texture;
9093 // R_Mesh_ResetTextureState();
9094 R_SetupShader_Generic_NoTexture(false, false);
9096 if(t && t->currentskinframe)
9098 memcpy(c, t->currentskinframe->avgcolor, sizeof(c));
9099 c[3] *= t->currentalpha;
9109 if (t->pantstexture || t->shirttexture)
9111 c[0] = 0.5 * (t->render_colormap_pants[0] * 0.3 + t->render_colormap_shirt[0] * 0.7);
9112 c[1] = 0.5 * (t->render_colormap_pants[1] * 0.3 + t->render_colormap_shirt[1] * 0.7);
9113 c[2] = 0.5 * (t->render_colormap_pants[2] * 0.3 + t->render_colormap_shirt[2] * 0.7);
9116 // brighten it up (as texture value 127 means "unlit")
9117 c[0] *= 2 * r_refdef.view.colorscale;
9118 c[1] *= 2 * r_refdef.view.colorscale;
9119 c[2] *= 2 * r_refdef.view.colorscale;
9121 if(t->currentmaterialflags & MATERIALFLAG_WATERALPHA)
9122 c[3] *= r_wateralpha.value;
9124 if(t->currentmaterialflags & MATERIALFLAG_ALPHA && c[3] != 1)
9126 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9127 GL_DepthMask(false);
9129 else if(t->currentmaterialflags & MATERIALFLAG_ADD)
9131 GL_BlendFunc(GL_ONE, GL_ONE);
9132 GL_DepthMask(false);
9134 else if(t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
9136 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // can't do alpha test without texture, so let's blend instead
9137 GL_DepthMask(false);
9139 else if(t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
9141 GL_BlendFunc(t->customblendfunc[0], t->customblendfunc[1]);
9142 GL_DepthMask(false);
9146 GL_BlendFunc(GL_ONE, GL_ZERO);
9147 GL_DepthMask(writedepth);
9150 if (!r_refdef.view.showdebug)
9152 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9153 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices);
9154 for (j = 0, vi = 0;j < rsurface.batchnumvertices;j++, vi++)
9156 VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
9157 Vector4Set(batchvertex[vi].color4f, 0, 0, 0, 1);
9159 R_Mesh_PrepareVertices_Generic_Unlock();
9162 else if (r_showsurfaces.integer == 4)
9164 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9165 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices);
9166 for (j = 0, vi = 0;j < rsurface.batchnumvertices;j++, vi++)
9168 float d = (vi << 3) * (1.0f / 256.0f);
9169 VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
9170 Vector4Set(batchvertex[vi].color4f, d, d, d, 1);
9172 R_Mesh_PrepareVertices_Generic_Unlock();
9175 else if (r_showsurfaces.integer == 2)
9178 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9179 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(3*rsurface.batchnumtriangles);
9180 for (j = 0, e = rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle;j < rsurface.batchnumtriangles;j++, e += 3)
9182 float d = ((j + rsurface.batchfirsttriangle) << 3) * (1.0f / 256.0f);
9183 VectorCopy(rsurface.batchvertex3f + 3*e[0], batchvertex[j*3+0].vertex3f);
9184 VectorCopy(rsurface.batchvertex3f + 3*e[1], batchvertex[j*3+1].vertex3f);
9185 VectorCopy(rsurface.batchvertex3f + 3*e[2], batchvertex[j*3+2].vertex3f);
9186 Vector4Set(batchvertex[j*3+0].color4f, d, d, d, 1);
9187 Vector4Set(batchvertex[j*3+1].color4f, d, d, d, 1);
9188 Vector4Set(batchvertex[j*3+2].color4f, d, d, d, 1);
9190 R_Mesh_PrepareVertices_Generic_Unlock();
9191 R_Mesh_Draw(0, rsurface.batchnumtriangles*3, 0, rsurface.batchnumtriangles, NULL, NULL, 0, NULL, NULL, 0);
9195 int texturesurfaceindex;
9197 const msurface_t *surface;
9198 float surfacecolor4f[4];
9199 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9200 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchfirstvertex + rsurface.batchnumvertices);
9202 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
9204 surface = texturesurfacelist[texturesurfaceindex];
9205 k = (int)(((size_t)surface) / sizeof(msurface_t));
9206 Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
9207 for (j = 0;j < surface->num_vertices;j++)
9209 VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
9210 Vector4Copy(surfacecolor4f, batchvertex[vi].color4f);
9214 R_Mesh_PrepareVertices_Generic_Unlock();
9219 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
9222 RSurf_SetupDepthAndCulling();
9223 if (r_showsurfaces.integer)
9225 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
9228 switch (vid.renderpath)
9230 case RENDERPATH_GL20:
9231 case RENDERPATH_GLES2:
9232 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
9238 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9241 int texturenumsurfaces, endsurface;
9243 const msurface_t *surface;
9244 const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
9246 RSurf_ActiveModelEntity(ent, true, true, false);
9248 if (r_transparentdepthmasking.integer)
9250 qboolean setup = false;
9251 for (i = 0;i < numsurfaces;i = j)
9254 surface = rsurface.modelsurfaces + surfacelist[i];
9255 texture = surface->texture;
9256 rsurface.texture = R_GetCurrentTexture(texture);
9257 rsurface.lightmaptexture = NULL;
9258 rsurface.deluxemaptexture = NULL;
9259 rsurface.uselightmaptexture = false;
9260 // scan ahead until we find a different texture
9261 endsurface = min(i + 1024, numsurfaces);
9262 texturenumsurfaces = 0;
9263 texturesurfacelist[texturenumsurfaces++] = surface;
9264 for (;j < endsurface;j++)
9266 surface = rsurface.modelsurfaces + surfacelist[j];
9267 if (texture != surface->texture)
9269 texturesurfacelist[texturenumsurfaces++] = surface;
9271 if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
9273 // render the range of surfaces as depth
9277 GL_ColorMask(0,0,0,0);
9280 GL_BlendFunc(GL_ONE, GL_ZERO);
9282 // R_Mesh_ResetTextureState();
9284 RSurf_SetupDepthAndCulling();
9285 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9286 R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9287 R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9291 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
9294 for (i = 0;i < numsurfaces;i = j)
9297 surface = rsurface.modelsurfaces + surfacelist[i];
9298 texture = surface->texture;
9299 rsurface.texture = R_GetCurrentTexture(texture);
9300 // scan ahead until we find a different texture
9301 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
9302 texturenumsurfaces = 0;
9303 texturesurfacelist[texturenumsurfaces++] = surface;
9304 if(FAKELIGHT_ENABLED)
9306 rsurface.lightmaptexture = NULL;
9307 rsurface.deluxemaptexture = NULL;
9308 rsurface.uselightmaptexture = false;
9309 for (;j < endsurface;j++)
9311 surface = rsurface.modelsurfaces + surfacelist[j];
9312 if (texture != surface->texture)
9314 texturesurfacelist[texturenumsurfaces++] = surface;
9319 rsurface.lightmaptexture = surface->lightmaptexture;
9320 rsurface.deluxemaptexture = surface->deluxemaptexture;
9321 rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
9322 for (;j < endsurface;j++)
9324 surface = rsurface.modelsurfaces + surfacelist[j];
9325 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
9327 texturesurfacelist[texturenumsurfaces++] = surface;
9330 // render the range of surfaces
9331 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false);
9333 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
9336 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9338 // transparent surfaces get pushed off into the transparent queue
9339 int surfacelistindex;
9340 const msurface_t *surface;
9341 vec3_t tempcenter, center;
9342 for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
9344 surface = texturesurfacelist[surfacelistindex];
9345 if (r_transparent_sortsurfacesbynearest.integer)
9347 tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
9348 tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
9349 tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
9353 tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
9354 tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
9355 tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
9357 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
9358 if (rsurface.entity->transparent_offset) // transparent offset
9360 center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
9361 center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
9362 center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
9364 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);
9368 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9370 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
9372 if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
9374 RSurf_SetupDepthAndCulling();
9375 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9376 R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9377 R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9381 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass)
9385 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
9388 if (!rsurface.texture->currentnumlayers)
9390 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
9391 R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9393 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
9395 else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
9396 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
9397 else if (!rsurface.texture->currentnumlayers)
9399 else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
9401 // in the deferred case, transparent surfaces were queued during prepass
9402 if (!r_shadow_usingdeferredprepass)
9403 R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9407 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
9408 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass);
9413 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass)
9417 R_FrameData_SetMark();
9418 // break the surface list down into batches by texture and use of lightmapping
9419 for (i = 0;i < numsurfaces;i = j)
9422 // texture is the base texture pointer, rsurface.texture is the
9423 // current frame/skin the texture is directing us to use (for example
9424 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
9425 // use skin 1 instead)
9426 texture = surfacelist[i]->texture;
9427 rsurface.texture = R_GetCurrentTexture(texture);
9428 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
9430 // if this texture is not the kind we want, skip ahead to the next one
9431 for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9435 if(FAKELIGHT_ENABLED || depthonly || prepass)
9437 rsurface.lightmaptexture = NULL;
9438 rsurface.deluxemaptexture = NULL;
9439 rsurface.uselightmaptexture = false;
9440 // simply scan ahead until we find a different texture or lightmap state
9441 for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9446 rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
9447 rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
9448 rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
9449 // simply scan ahead until we find a different texture or lightmap state
9450 for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
9453 // render the range of surfaces
9454 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass);
9456 R_FrameData_ReturnToMark();
9459 float locboxvertex3f[6*4*3] =
9461 1,0,1, 1,0,0, 1,1,0, 1,1,1,
9462 0,1,1, 0,1,0, 0,0,0, 0,0,1,
9463 1,1,1, 1,1,0, 0,1,0, 0,1,1,
9464 0,0,1, 0,0,0, 1,0,0, 1,0,1,
9465 0,0,1, 1,0,1, 1,1,1, 0,1,1,
9466 1,0,0, 0,0,0, 0,1,0, 1,1,0
9469 unsigned short locboxelements[6*2*3] =
9479 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9482 cl_locnode_t *loc = (cl_locnode_t *)ent;
9484 float vertex3f[6*4*3];
9486 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9487 GL_DepthMask(false);
9488 GL_DepthRange(0, 1);
9489 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9491 GL_CullFace(GL_NONE);
9492 R_EntityMatrix(&identitymatrix);
9494 // R_Mesh_ResetTextureState();
9497 GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9498 ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9499 ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9500 surfacelist[0] < 0 ? 0.5f : 0.125f);
9502 if (VectorCompare(loc->mins, loc->maxs))
9504 VectorSet(size, 2, 2, 2);
9505 VectorMA(loc->mins, -0.5f, size, mins);
9509 VectorCopy(loc->mins, mins);
9510 VectorSubtract(loc->maxs, loc->mins, size);
9513 for (i = 0;i < 6*4*3;)
9514 for (j = 0;j < 3;j++, i++)
9515 vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9517 R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9518 R_SetupShader_Generic_NoTexture(false, false);
9519 R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9522 void R_DrawLocs(void)
9525 cl_locnode_t *loc, *nearestloc;
9527 nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9528 for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9530 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9531 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9535 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9537 if (decalsystem->decals)
9538 Mem_Free(decalsystem->decals);
9539 memset(decalsystem, 0, sizeof(*decalsystem));
9542 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)
9548 // expand or initialize the system
9549 if (decalsystem->maxdecals <= decalsystem->numdecals)
9551 decalsystem_t old = *decalsystem;
9552 qboolean useshortelements;
9553 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9554 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9555 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)));
9556 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9557 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9558 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9559 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9560 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9561 if (decalsystem->numdecals)
9562 memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9564 Mem_Free(old.decals);
9565 for (i = 0;i < decalsystem->maxdecals*3;i++)
9566 decalsystem->element3i[i] = i;
9567 if (useshortelements)
9568 for (i = 0;i < decalsystem->maxdecals*3;i++)
9569 decalsystem->element3s[i] = i;
9572 // grab a decal and search for another free slot for the next one
9573 decals = decalsystem->decals;
9574 decal = decalsystem->decals + (i = decalsystem->freedecal++);
9575 for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9577 decalsystem->freedecal = i;
9578 if (decalsystem->numdecals <= i)
9579 decalsystem->numdecals = i + 1;
9581 // initialize the decal
9583 decal->triangleindex = triangleindex;
9584 decal->surfaceindex = surfaceindex;
9585 decal->decalsequence = decalsequence;
9586 decal->color4f[0][0] = c0[0];
9587 decal->color4f[0][1] = c0[1];
9588 decal->color4f[0][2] = c0[2];
9589 decal->color4f[0][3] = 1;
9590 decal->color4f[1][0] = c1[0];
9591 decal->color4f[1][1] = c1[1];
9592 decal->color4f[1][2] = c1[2];
9593 decal->color4f[1][3] = 1;
9594 decal->color4f[2][0] = c2[0];
9595 decal->color4f[2][1] = c2[1];
9596 decal->color4f[2][2] = c2[2];
9597 decal->color4f[2][3] = 1;
9598 decal->vertex3f[0][0] = v0[0];
9599 decal->vertex3f[0][1] = v0[1];
9600 decal->vertex3f[0][2] = v0[2];
9601 decal->vertex3f[1][0] = v1[0];
9602 decal->vertex3f[1][1] = v1[1];
9603 decal->vertex3f[1][2] = v1[2];
9604 decal->vertex3f[2][0] = v2[0];
9605 decal->vertex3f[2][1] = v2[1];
9606 decal->vertex3f[2][2] = v2[2];
9607 decal->texcoord2f[0][0] = t0[0];
9608 decal->texcoord2f[0][1] = t0[1];
9609 decal->texcoord2f[1][0] = t1[0];
9610 decal->texcoord2f[1][1] = t1[1];
9611 decal->texcoord2f[2][0] = t2[0];
9612 decal->texcoord2f[2][1] = t2[1];
9613 TriangleNormal(v0, v1, v2, decal->plane);
9614 VectorNormalize(decal->plane);
9615 decal->plane[3] = DotProduct(v0, decal->plane);
9618 extern cvar_t cl_decals_bias;
9619 extern cvar_t cl_decals_models;
9620 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9621 // baseparms, parms, temps
9622 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)
9627 const float *vertex3f;
9628 const float *normal3f;
9630 float points[2][9][3];
9637 e = rsurface.modelelement3i + 3*triangleindex;
9639 vertex3f = rsurface.modelvertex3f;
9640 normal3f = rsurface.modelnormal3f;
9644 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9646 index = 3*e[cornerindex];
9647 VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9652 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9654 index = 3*e[cornerindex];
9655 VectorCopy(vertex3f + index, v[cornerindex]);
9660 //TriangleNormal(v[0], v[1], v[2], normal);
9661 //if (DotProduct(normal, localnormal) < 0.0f)
9663 // clip by each of the box planes formed from the projection matrix
9664 // if anything survives, we emit the decal
9665 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]);
9668 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]);
9671 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]);
9674 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]);
9677 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]);
9680 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]);
9683 // some part of the triangle survived, so we have to accept it...
9686 // dynamic always uses the original triangle
9688 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9690 index = 3*e[cornerindex];
9691 VectorCopy(vertex3f + index, v[cornerindex]);
9694 for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9696 // convert vertex positions to texcoords
9697 Matrix4x4_Transform(projection, v[cornerindex], temp);
9698 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9699 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9700 // calculate distance fade from the projection origin
9701 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9702 f = bound(0.0f, f, 1.0f);
9703 c[cornerindex][0] = r * f;
9704 c[cornerindex][1] = g * f;
9705 c[cornerindex][2] = b * f;
9706 c[cornerindex][3] = 1.0f;
9707 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9710 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);
9712 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9713 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);
9715 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)
9717 matrix4x4_t projection;
9718 decalsystem_t *decalsystem;
9721 const msurface_t *surface;
9722 const msurface_t *surfaces;
9723 const int *surfacelist;
9724 const texture_t *texture;
9727 int surfacelistindex;
9730 float localorigin[3];
9731 float localnormal[3];
9739 int bih_triangles_count;
9740 int bih_triangles[256];
9741 int bih_surfaces[256];
9743 decalsystem = &ent->decalsystem;
9745 if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9747 R_DecalSystem_Reset(&ent->decalsystem);
9751 if (!model->brush.data_leafs && !cl_decals_models.integer)
9753 if (decalsystem->model)
9754 R_DecalSystem_Reset(decalsystem);
9758 if (decalsystem->model != model)
9759 R_DecalSystem_Reset(decalsystem);
9760 decalsystem->model = model;
9762 RSurf_ActiveModelEntity(ent, true, false, false);
9764 Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9765 Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9766 VectorNormalize(localnormal);
9767 localsize = worldsize*rsurface.inversematrixscale;
9768 localmins[0] = localorigin[0] - localsize;
9769 localmins[1] = localorigin[1] - localsize;
9770 localmins[2] = localorigin[2] - localsize;
9771 localmaxs[0] = localorigin[0] + localsize;
9772 localmaxs[1] = localorigin[1] + localsize;
9773 localmaxs[2] = localorigin[2] + localsize;
9775 //VectorCopy(localnormal, planes[4]);
9776 //VectorVectors(planes[4], planes[2], planes[0]);
9777 AnglesFromVectors(angles, localnormal, NULL, false);
9778 AngleVectors(angles, planes[0], planes[2], planes[4]);
9779 VectorNegate(planes[0], planes[1]);
9780 VectorNegate(planes[2], planes[3]);
9781 VectorNegate(planes[4], planes[5]);
9782 planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9783 planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9784 planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9785 planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9786 planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9787 planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9792 matrix4x4_t forwardprojection;
9793 Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9794 Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9799 float projectionvector[4][3];
9800 VectorScale(planes[0], ilocalsize, projectionvector[0]);
9801 VectorScale(planes[2], ilocalsize, projectionvector[1]);
9802 VectorScale(planes[4], ilocalsize, projectionvector[2]);
9803 projectionvector[0][0] = planes[0][0] * ilocalsize;
9804 projectionvector[0][1] = planes[1][0] * ilocalsize;
9805 projectionvector[0][2] = planes[2][0] * ilocalsize;
9806 projectionvector[1][0] = planes[0][1] * ilocalsize;
9807 projectionvector[1][1] = planes[1][1] * ilocalsize;
9808 projectionvector[1][2] = planes[2][1] * ilocalsize;
9809 projectionvector[2][0] = planes[0][2] * ilocalsize;
9810 projectionvector[2][1] = planes[1][2] * ilocalsize;
9811 projectionvector[2][2] = planes[2][2] * ilocalsize;
9812 projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9813 projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9814 projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9815 Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9819 dynamic = model->surfmesh.isanimated;
9820 numsurfacelist = model->nummodelsurfaces;
9821 surfacelist = model->sortedmodelsurfaces;
9822 surfaces = model->data_surfaces;
9825 bih_triangles_count = -1;
9828 if(model->render_bih.numleafs)
9829 bih = &model->render_bih;
9830 else if(model->collision_bih.numleafs)
9831 bih = &model->collision_bih;
9834 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9835 if(bih_triangles_count == 0)
9837 if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9839 if(bih_triangles_count > 0)
9841 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9843 surfaceindex = bih_surfaces[triangleindex];
9844 surface = surfaces + surfaceindex;
9845 texture = surface->texture;
9846 if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9848 if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9850 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9855 for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
9857 surfaceindex = surfacelist[surfacelistindex];
9858 surface = surfaces + surfaceindex;
9859 // check cull box first because it rejects more than any other check
9860 if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9862 // skip transparent surfaces
9863 texture = surface->texture;
9864 if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9866 if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9868 numtriangles = surface->num_triangles;
9869 for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9870 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9875 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9876 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)
9878 int renderentityindex;
9881 entity_render_t *ent;
9883 if (!cl_decals_newsystem.integer)
9886 worldmins[0] = worldorigin[0] - worldsize;
9887 worldmins[1] = worldorigin[1] - worldsize;
9888 worldmins[2] = worldorigin[2] - worldsize;
9889 worldmaxs[0] = worldorigin[0] + worldsize;
9890 worldmaxs[1] = worldorigin[1] + worldsize;
9891 worldmaxs[2] = worldorigin[2] + worldsize;
9893 R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9895 for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9897 ent = r_refdef.scene.entities[renderentityindex];
9898 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9901 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9905 typedef struct r_decalsystem_splatqueue_s
9912 unsigned int decalsequence;
9914 r_decalsystem_splatqueue_t;
9916 int r_decalsystem_numqueued = 0;
9917 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9919 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)
9921 r_decalsystem_splatqueue_t *queue;
9923 if (!cl_decals_newsystem.integer || r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9926 queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9927 VectorCopy(worldorigin, queue->worldorigin);
9928 VectorCopy(worldnormal, queue->worldnormal);
9929 Vector4Set(queue->color, r, g, b, a);
9930 Vector4Set(queue->tcrange, s1, t1, s2, t2);
9931 queue->worldsize = worldsize;
9932 queue->decalsequence = cl.decalsequence++;
9935 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9938 r_decalsystem_splatqueue_t *queue;
9940 for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9941 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);
9942 r_decalsystem_numqueued = 0;
9945 extern cvar_t cl_decals_max;
9946 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9949 decalsystem_t *decalsystem = &ent->decalsystem;
9951 unsigned int killsequence;
9956 if (!decalsystem->numdecals)
9959 if (r_showsurfaces.integer)
9962 if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9964 R_DecalSystem_Reset(decalsystem);
9968 killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9969 lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9971 if (decalsystem->lastupdatetime)
9972 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9975 decalsystem->lastupdatetime = r_refdef.scene.time;
9976 numdecals = decalsystem->numdecals;
9978 for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9980 if (decal->color4f[0][3])
9982 decal->lived += frametime;
9983 if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9985 memset(decal, 0, sizeof(*decal));
9986 if (decalsystem->freedecal > i)
9987 decalsystem->freedecal = i;
9991 decal = decalsystem->decals;
9992 while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9995 // collapse the array by shuffling the tail decals into the gaps
9998 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
9999 decalsystem->freedecal++;
10000 if (decalsystem->freedecal == numdecals)
10002 decal[decalsystem->freedecal] = decal[--numdecals];
10005 decalsystem->numdecals = numdecals;
10007 if (numdecals <= 0)
10009 // if there are no decals left, reset decalsystem
10010 R_DecalSystem_Reset(decalsystem);
10014 extern skinframe_t *decalskinframe;
10015 static void R_DrawModelDecals_Entity(entity_render_t *ent)
10018 decalsystem_t *decalsystem = &ent->decalsystem;
10027 const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
10030 numdecals = decalsystem->numdecals;
10034 if (r_showsurfaces.integer)
10037 if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
10039 R_DecalSystem_Reset(decalsystem);
10043 // if the model is static it doesn't matter what value we give for
10044 // wantnormals and wanttangents, so this logic uses only rules applicable
10045 // to a model, knowing that they are meaningless otherwise
10046 RSurf_ActiveModelEntity(ent, false, false, false);
10048 decalsystem->lastupdatetime = r_refdef.scene.time;
10050 faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
10052 // update vertex positions for animated models
10053 v3f = decalsystem->vertex3f;
10054 c4f = decalsystem->color4f;
10055 t2f = decalsystem->texcoord2f;
10056 for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
10058 if (!decal->color4f[0][3])
10061 if (surfacevisible && !surfacevisible[decal->surfaceindex])
10065 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
10068 // update color values for fading decals
10069 if (decal->lived >= cl_decals_time.value)
10070 alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
10074 c4f[ 0] = decal->color4f[0][0] * alpha;
10075 c4f[ 1] = decal->color4f[0][1] * alpha;
10076 c4f[ 2] = decal->color4f[0][2] * alpha;
10078 c4f[ 4] = decal->color4f[1][0] * alpha;
10079 c4f[ 5] = decal->color4f[1][1] * alpha;
10080 c4f[ 6] = decal->color4f[1][2] * alpha;
10082 c4f[ 8] = decal->color4f[2][0] * alpha;
10083 c4f[ 9] = decal->color4f[2][1] * alpha;
10084 c4f[10] = decal->color4f[2][2] * alpha;
10087 t2f[0] = decal->texcoord2f[0][0];
10088 t2f[1] = decal->texcoord2f[0][1];
10089 t2f[2] = decal->texcoord2f[1][0];
10090 t2f[3] = decal->texcoord2f[1][1];
10091 t2f[4] = decal->texcoord2f[2][0];
10092 t2f[5] = decal->texcoord2f[2][1];
10094 // update vertex positions for animated models
10095 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
10097 e = rsurface.modelelement3i + 3*decal->triangleindex;
10098 VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
10099 VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
10100 VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
10104 VectorCopy(decal->vertex3f[0], v3f);
10105 VectorCopy(decal->vertex3f[1], v3f + 3);
10106 VectorCopy(decal->vertex3f[2], v3f + 6);
10109 if (r_refdef.fogenabled)
10111 alpha = RSurf_FogVertex(v3f);
10112 VectorScale(c4f, alpha, c4f);
10113 alpha = RSurf_FogVertex(v3f + 3);
10114 VectorScale(c4f + 4, alpha, c4f + 4);
10115 alpha = RSurf_FogVertex(v3f + 6);
10116 VectorScale(c4f + 8, alpha, c4f + 8);
10127 r_refdef.stats[r_stat_drawndecals] += numtris;
10129 // now render the decals all at once
10130 // (this assumes they all use one particle font texture!)
10131 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);
10132 // R_Mesh_ResetTextureState();
10133 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
10134 GL_DepthMask(false);
10135 GL_DepthRange(0, 1);
10136 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
10137 GL_DepthTest(true);
10138 GL_CullFace(GL_NONE);
10139 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
10140 R_SetupShader_Generic(decalskinframe->base, NULL, GL_MODULATE, 1, false, false, false);
10141 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
10145 static void R_DrawModelDecals(void)
10149 // fade faster when there are too many decals
10150 numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
10151 for (i = 0;i < r_refdef.scene.numentities;i++)
10152 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
10154 R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
10155 for (i = 0;i < r_refdef.scene.numentities;i++)
10156 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
10157 R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
10159 R_DecalSystem_ApplySplatEntitiesQueue();
10161 numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
10162 for (i = 0;i < r_refdef.scene.numentities;i++)
10163 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
10165 r_refdef.stats[r_stat_totaldecals] += numdecals;
10167 if (r_showsurfaces.integer)
10170 R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
10172 for (i = 0;i < r_refdef.scene.numentities;i++)
10174 if (!r_refdef.viewcache.entityvisible[i])
10176 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
10177 R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
10181 extern cvar_t mod_collision_bih;
10182 static void R_DrawDebugModel(void)
10184 entity_render_t *ent = rsurface.entity;
10185 int i, j, flagsmask;
10186 const msurface_t *surface;
10187 dp_model_t *model = ent->model;
10189 if (!sv.active && !cls.demoplayback && ent != r_refdef.scene.worldentity)
10192 if (r_showoverdraw.value > 0)
10194 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
10195 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
10196 R_SetupShader_Generic_NoTexture(false, false);
10197 GL_DepthTest(false);
10198 GL_DepthMask(false);
10199 GL_DepthRange(0, 1);
10200 GL_BlendFunc(GL_ONE, GL_ONE);
10201 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10203 if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10205 rsurface.texture = R_GetCurrentTexture(surface->texture);
10206 if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10208 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
10209 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
10210 if (!rsurface.texture->currentlayers->depthmask)
10211 GL_Color(c, 0, 0, 1.0f);
10212 else if (ent == r_refdef.scene.worldentity)
10213 GL_Color(c, c, c, 1.0f);
10215 GL_Color(0, c, 0, 1.0f);
10216 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
10220 rsurface.texture = NULL;
10223 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
10225 // R_Mesh_ResetTextureState();
10226 R_SetupShader_Generic_NoTexture(false, false);
10227 GL_DepthRange(0, 1);
10228 GL_DepthTest(!r_showdisabledepthtest.integer);
10229 GL_DepthMask(false);
10230 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10232 if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
10236 qboolean cullbox = false;
10237 const q3mbrush_t *brush;
10238 const bih_t *bih = &model->collision_bih;
10239 const bih_leaf_t *bihleaf;
10240 float vertex3f[3][3];
10241 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
10242 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
10244 if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
10246 switch (bihleaf->type)
10249 brush = model->brush.data_brushes + bihleaf->itemindex;
10250 if (brush->colbrushf && brush->colbrushf->numtriangles)
10252 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);
10253 R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
10254 R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
10257 case BIH_COLLISIONTRIANGLE:
10258 triangleindex = bihleaf->itemindex;
10259 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
10260 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
10261 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
10262 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);
10263 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
10264 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
10266 case BIH_RENDERTRIANGLE:
10267 triangleindex = bihleaf->itemindex;
10268 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
10269 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
10270 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
10271 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);
10272 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
10273 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
10279 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
10282 if (r_showtris.value > 0 && qglPolygonMode)
10284 if (r_showdisabledepthtest.integer)
10286 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10287 GL_DepthMask(false);
10291 GL_BlendFunc(GL_ONE, GL_ZERO);
10292 GL_DepthMask(true);
10294 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
10295 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10297 if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10299 rsurface.texture = R_GetCurrentTexture(surface->texture);
10300 if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10302 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
10303 if (!rsurface.texture->currentlayers->depthmask)
10304 GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
10305 else if (ent == r_refdef.scene.worldentity)
10306 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
10308 GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
10309 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
10313 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
10314 rsurface.texture = NULL;
10318 // FIXME! implement r_shownormals with just triangles
10319 if (r_shownormals.value != 0 && qglBegin)
10323 if (r_showdisabledepthtest.integer)
10325 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10326 GL_DepthMask(false);
10330 GL_BlendFunc(GL_ONE, GL_ZERO);
10331 GL_DepthMask(true);
10333 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10335 if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10337 rsurface.texture = R_GetCurrentTexture(surface->texture);
10338 if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10340 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
10341 qglBegin(GL_LINES);
10342 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
10344 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10346 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10347 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10348 qglVertex3f(v[0], v[1], v[2]);
10349 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10350 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10351 qglVertex3f(v[0], v[1], v[2]);
10354 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
10356 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10358 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10359 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
10360 qglVertex3f(v[0], v[1], v[2]);
10361 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
10362 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10363 qglVertex3f(v[0], v[1], v[2]);
10366 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
10368 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10370 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10371 GL_Color(0, r_refdef.view.colorscale, 0, 1);
10372 qglVertex3f(v[0], v[1], v[2]);
10373 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
10374 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10375 qglVertex3f(v[0], v[1], v[2]);
10378 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
10380 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10382 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10383 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10384 qglVertex3f(v[0], v[1], v[2]);
10385 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10386 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10387 qglVertex3f(v[0], v[1], v[2]);
10394 rsurface.texture = NULL;
10400 int r_maxsurfacelist = 0;
10401 const msurface_t **r_surfacelist = NULL;
10402 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass)
10404 int i, j, endj, flagsmask;
10405 dp_model_t *model = ent->model;
10406 msurface_t *surfaces;
10407 unsigned char *update;
10408 int numsurfacelist = 0;
10412 if (r_maxsurfacelist < model->num_surfaces)
10414 r_maxsurfacelist = model->num_surfaces;
10416 Mem_Free((msurface_t **)r_surfacelist);
10417 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
10420 if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
10421 RSurf_ActiveModelEntity(ent, false, false, false);
10423 RSurf_ActiveModelEntity(ent, true, true, true);
10424 else if (depthonly)
10425 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
10427 RSurf_ActiveModelEntity(ent, true, true, false);
10429 surfaces = model->data_surfaces;
10430 update = model->brushq1.lightmapupdateflags;
10432 // update light styles
10433 if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0)
10435 model_brush_lightstyleinfo_t *style;
10436 for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
10438 if (style->value != r_refdef.scene.lightstylevalue[style->style])
10440 int *list = style->surfacelist;
10441 style->value = r_refdef.scene.lightstylevalue[style->style];
10442 for (j = 0;j < style->numsurfaces;j++)
10443 update[list[j]] = true;
10448 flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
10452 R_DrawDebugModel();
10453 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10457 rsurface.lightmaptexture = NULL;
10458 rsurface.deluxemaptexture = NULL;
10459 rsurface.uselightmaptexture = false;
10460 rsurface.texture = NULL;
10461 rsurface.rtlight = NULL;
10462 numsurfacelist = 0;
10463 // add visible surfaces to draw list
10464 if (ent == r_refdef.scene.worldentity)
10466 // for the world entity, check surfacevisible
10467 for (i = 0;i < model->nummodelsurfaces;i++)
10469 j = model->sortedmodelsurfaces[i];
10470 if (r_refdef.viewcache.world_surfacevisible[j])
10471 r_surfacelist[numsurfacelist++] = surfaces + j;
10476 // add all surfaces
10477 for (i = 0; i < model->nummodelsurfaces; i++)
10478 r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
10480 // don't do anything if there were no surfaces
10481 if (!numsurfacelist)
10483 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10486 // update lightmaps if needed
10490 for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
10495 R_BuildLightMap(ent, surfaces + j);
10500 R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass);
10502 // add to stats if desired
10503 if (r_speeds.integer && !skysurfaces && !depthonly)
10505 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10506 for (j = 0;j < numsurfacelist;j++)
10507 r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10510 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10513 void R_DebugLine(vec3_t start, vec3_t end)
10515 dp_model_t *mod = CL_Mesh_UI();
10517 int e0, e1, e2, e3;
10518 float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10519 float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10520 float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10523 // transform to screen coords first
10524 Vector4Set(w[0], start[0], start[1], start[2], 1);
10525 Vector4Set(w[1], end[0], end[1], end[2], 1);
10526 R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10527 R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10528 x1 = s[0][0] * vid_conwidth.value / vid.width;
10529 y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10530 x2 = s[1][0] * vid_conwidth.value / vid.width;
10531 y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10532 //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10534 // add the line to the UI mesh for drawing later
10536 // width is measured in real pixels
10537 if (fabs(x2 - x1) > fabs(y2 - y1))
10540 offsety = 0.5f * width * vid_conheight.value / vid.height;
10544 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10547 surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_VERTEXCOLOR), true);
10548 e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10549 e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10550 e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10551 e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10552 Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10553 Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10558 void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass)
10561 static texture_t texture;
10562 static msurface_t surface;
10563 const msurface_t *surfacelist = &surface;
10565 // fake enough texture and surface state to render this geometry
10567 texture.update_lastrenderframe = -1; // regenerate this texture
10568 texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10569 texture.basealpha = 1.0f;
10570 texture.currentskinframe = skinframe;
10571 texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10572 texture.offsetmapping = OFFSETMAPPING_OFF;
10573 texture.offsetscale = 1;
10574 texture.specularscalemod = 1;
10575 texture.specularpowermod = 1;
10576 texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10577 // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
10578 // JUST GREP FOR "specularscalemod = 1".
10580 for (q = 0; q < 3; q++)
10582 texture.render_glowmod[q] = r_refdef.view.colorscale * r_hdr_glowintensity.value;
10583 texture.render_modellight_lightdir[q] = q == 2;
10584 texture.render_modellight_ambient[q] = r_refdef.view.colorscale * r_refdef.scene.ambientintensity;
10585 texture.render_modellight_diffuse[q] = r_refdef.view.colorscale;
10586 texture.render_modellight_specular[q] = r_refdef.view.colorscale;
10587 texture.render_lightmap_ambient[q] = r_refdef.view.colorscale * r_refdef.scene.ambientintensity;
10588 texture.render_lightmap_diffuse[q] = r_refdef.view.colorscale * r_refdef.scene.lightmapintensity;
10589 texture.render_lightmap_specular[q] = r_refdef.view.colorscale;
10590 texture.render_rtlight_diffuse[q] = r_refdef.view.colorscale;
10591 texture.render_rtlight_specular[q] = r_refdef.view.colorscale;
10593 texture.currentalpha = 1.0f;
10595 surface.texture = &texture;
10596 surface.num_triangles = numtriangles;
10597 surface.num_firsttriangle = firsttriangle;
10598 surface.num_vertices = numvertices;
10599 surface.num_firstvertex = firstvertex;
10602 rsurface.texture = R_GetCurrentTexture(surface.texture);
10603 rsurface.lightmaptexture = NULL;
10604 rsurface.deluxemaptexture = NULL;
10605 rsurface.uselightmaptexture = false;
10606 R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);
10609 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)
10611 static msurface_t surface;
10612 const msurface_t *surfacelist = &surface;
10614 // fake enough texture and surface state to render this geometry
10615 surface.texture = texture;
10616 surface.num_triangles = numtriangles;
10617 surface.num_firsttriangle = firsttriangle;
10618 surface.num_vertices = numvertices;
10619 surface.num_firstvertex = firstvertex;
10622 rsurface.texture = R_GetCurrentTexture(surface.texture);
10623 rsurface.lightmaptexture = NULL;
10624 rsurface.deluxemaptexture = NULL;
10625 rsurface.uselightmaptexture = false;
10626 R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);