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 extern cvar_t gl_picmip;
2282 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2285 unsigned char *pixels;
2286 unsigned char *bumppixels;
2287 unsigned char *basepixels = NULL;
2288 int basepixels_width = 0;
2289 int basepixels_height = 0;
2290 skinframe_t *skinframe;
2291 rtexture_t *ddsbase = NULL;
2292 qboolean ddshasalpha = false;
2293 float ddsavgcolor[4];
2294 char basename[MAX_QPATH];
2295 int miplevel = R_PicmipForFlags(textureflags);
2296 int savemiplevel = miplevel;
2300 if (cls.state == ca_dedicated)
2303 // return an existing skinframe if already loaded
2304 // if loading of the first image fails, don't make a new skinframe as it
2305 // would cause all future lookups of this to be missing
2306 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, -1, false);
2307 if (skinframe && skinframe->base)
2310 Image_StripImageExtension(name, basename, sizeof(basename));
2312 // check for DDS texture file first
2313 if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2315 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2316 if (basepixels == NULL && fallbacknotexture)
2317 basepixels = Image_GenerateNoTexture();
2318 if (basepixels == NULL)
2322 // FIXME handle miplevel
2324 if (developer_loading.integer)
2325 Con_Printf("loading skin \"%s\"\n", name);
2327 // we've got some pixels to store, so really allocate this new texture now
2329 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2330 textureflags &= ~TEXF_FORCE_RELOAD;
2331 skinframe->stain = NULL;
2332 skinframe->merged = NULL;
2333 skinframe->base = NULL;
2334 skinframe->pants = NULL;
2335 skinframe->shirt = NULL;
2336 skinframe->nmap = NULL;
2337 skinframe->gloss = NULL;
2338 skinframe->glow = NULL;
2339 skinframe->fog = NULL;
2340 skinframe->reflect = NULL;
2341 skinframe->hasalpha = false;
2342 // we could store the q2animname here too
2346 skinframe->base = ddsbase;
2347 skinframe->hasalpha = ddshasalpha;
2348 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2349 if (r_loadfog && skinframe->hasalpha)
2350 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);
2351 //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]);
2355 basepixels_width = image_width;
2356 basepixels_height = image_height;
2357 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);
2358 if (textureflags & TEXF_ALPHA)
2360 for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2362 if (basepixels[j] < 255)
2364 skinframe->hasalpha = true;
2368 if (r_loadfog && skinframe->hasalpha)
2370 // has transparent pixels
2371 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2372 for (j = 0;j < image_width * image_height * 4;j += 4)
2377 pixels[j+3] = basepixels[j+3];
2379 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);
2383 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2385 //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]);
2386 if (r_savedds && qglGetCompressedTexImageARB && skinframe->base)
2387 R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2388 if (r_savedds && qglGetCompressedTexImageARB && skinframe->fog)
2389 R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2395 mymiplevel = savemiplevel;
2396 if (r_loadnormalmap)
2397 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);
2398 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2400 skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2401 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2402 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2403 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2406 // _norm is the name used by tenebrae and has been adopted as standard
2407 if (r_loadnormalmap && skinframe->nmap == NULL)
2409 mymiplevel = savemiplevel;
2410 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2412 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);
2416 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2418 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2419 Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2420 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);
2422 Mem_Free(bumppixels);
2424 else if (r_shadow_bumpscale_basetexture.value > 0)
2426 pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2427 Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2428 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);
2432 if (r_savedds && qglGetCompressedTexImageARB && skinframe->nmap)
2433 R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2437 // _luma is supported only for tenebrae compatibility
2438 // _glow is the preferred name
2439 mymiplevel = savemiplevel;
2440 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))))
2442 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);
2444 if (r_savedds && qglGetCompressedTexImageARB && skinframe->glow)
2445 R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2447 Mem_Free(pixels);pixels = NULL;
2450 mymiplevel = savemiplevel;
2451 if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2453 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);
2455 if (r_savedds && qglGetCompressedTexImageARB && skinframe->gloss)
2456 R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2462 mymiplevel = savemiplevel;
2463 if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2465 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);
2467 if (r_savedds && qglGetCompressedTexImageARB && skinframe->pants)
2468 R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2474 mymiplevel = savemiplevel;
2475 if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2477 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);
2479 if (r_savedds && qglGetCompressedTexImageARB && skinframe->shirt)
2480 R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2486 mymiplevel = savemiplevel;
2487 if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2489 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);
2491 if (r_savedds && qglGetCompressedTexImageARB && skinframe->reflect)
2492 R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2499 Mem_Free(basepixels);
2504 // this is only used by .spr32 sprites, HL .spr files, HL .bsp files
2505 skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, qboolean sRGB)
2508 skinframe_t *skinframe;
2511 if (cls.state == ca_dedicated)
2514 // if already loaded just return it, otherwise make a new skinframe
2515 skinframe = R_SkinFrame_Find(name, textureflags, width, height, (textureflags & TEXF_FORCE_RELOAD) ? -1 : skindata ? CRC_Block(skindata, width*height*4) : 0, true);
2516 if (skinframe->base)
2518 textureflags &= ~TEXF_FORCE_RELOAD;
2520 skinframe->stain = NULL;
2521 skinframe->merged = NULL;
2522 skinframe->base = NULL;
2523 skinframe->pants = NULL;
2524 skinframe->shirt = NULL;
2525 skinframe->nmap = NULL;
2526 skinframe->gloss = NULL;
2527 skinframe->glow = NULL;
2528 skinframe->fog = NULL;
2529 skinframe->reflect = NULL;
2530 skinframe->hasalpha = false;
2532 // if no data was provided, then clearly the caller wanted to get a blank skinframe
2536 if (developer_loading.integer)
2537 Con_Printf("loading 32bit skin \"%s\"\n", name);
2539 if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2541 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2542 unsigned char *b = a + width * height * 4;
2543 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2544 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);
2547 skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2548 if (textureflags & TEXF_ALPHA)
2550 for (i = 3;i < width * height * 4;i += 4)
2552 if (skindata[i] < 255)
2554 skinframe->hasalpha = true;
2558 if (r_loadfog && skinframe->hasalpha)
2560 unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2561 memcpy(fogpixels, skindata, width * height * 4);
2562 for (i = 0;i < width * height * 4;i += 4)
2563 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2564 skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2565 Mem_Free(fogpixels);
2569 R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2570 //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]);
2575 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2579 skinframe_t *skinframe;
2581 if (cls.state == ca_dedicated)
2584 // if already loaded just return it, otherwise make a new skinframe
2585 skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2586 if (skinframe->base)
2588 //textureflags &= ~TEXF_FORCE_RELOAD;
2590 skinframe->stain = NULL;
2591 skinframe->merged = NULL;
2592 skinframe->base = NULL;
2593 skinframe->pants = NULL;
2594 skinframe->shirt = NULL;
2595 skinframe->nmap = NULL;
2596 skinframe->gloss = NULL;
2597 skinframe->glow = NULL;
2598 skinframe->fog = NULL;
2599 skinframe->reflect = NULL;
2600 skinframe->hasalpha = false;
2602 // if no data was provided, then clearly the caller wanted to get a blank skinframe
2606 if (developer_loading.integer)
2607 Con_Printf("loading quake skin \"%s\"\n", name);
2609 // 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)
2610 skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2611 memcpy(skinframe->qpixels, skindata, width*height);
2612 skinframe->qwidth = width;
2613 skinframe->qheight = height;
2616 for (i = 0;i < width * height;i++)
2617 featuresmask |= palette_featureflags[skindata[i]];
2619 skinframe->hasalpha = false;
2622 skinframe->hasalpha = true;
2623 skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2624 skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2625 skinframe->qgeneratemerged = true;
2626 skinframe->qgeneratebase = skinframe->qhascolormapping;
2627 skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2629 R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2630 //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]);
2635 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboolean colormapped)
2639 unsigned char *skindata;
2642 if (!skinframe->qpixels)
2645 if (!skinframe->qhascolormapping)
2646 colormapped = false;
2650 if (!skinframe->qgeneratebase)
2655 if (!skinframe->qgeneratemerged)
2659 width = skinframe->qwidth;
2660 height = skinframe->qheight;
2661 skindata = skinframe->qpixels;
2663 if (skinframe->qgeneratenmap)
2665 unsigned char *a, *b;
2666 skinframe->qgeneratenmap = false;
2667 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2668 b = a + width * height * 4;
2669 // use either a custom palette or the quake palette
2670 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2671 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2672 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);
2676 if (skinframe->qgenerateglow)
2678 skinframe->qgenerateglow = false;
2679 if (skinframe->hasalpha) // fence textures
2680 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
2682 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
2687 skinframe->qgeneratebase = false;
2688 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);
2689 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);
2690 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);
2694 skinframe->qgeneratemerged = false;
2695 if (skinframe->hasalpha) // fence textures
2696 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);
2698 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);
2701 if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2703 Mem_Free(skinframe->qpixels);
2704 skinframe->qpixels = NULL;
2708 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)
2711 skinframe_t *skinframe;
2714 if (cls.state == ca_dedicated)
2717 // if already loaded just return it, otherwise make a new skinframe
2718 skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2719 if (skinframe->base)
2721 textureflags &= ~TEXF_FORCE_RELOAD;
2723 skinframe->stain = NULL;
2724 skinframe->merged = NULL;
2725 skinframe->base = NULL;
2726 skinframe->pants = NULL;
2727 skinframe->shirt = NULL;
2728 skinframe->nmap = NULL;
2729 skinframe->gloss = NULL;
2730 skinframe->glow = NULL;
2731 skinframe->fog = NULL;
2732 skinframe->reflect = NULL;
2733 skinframe->hasalpha = false;
2735 // if no data was provided, then clearly the caller wanted to get a blank skinframe
2739 if (developer_loading.integer)
2740 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2742 skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2743 if ((textureflags & TEXF_ALPHA) && alphapalette)
2745 for (i = 0;i < width * height;i++)
2747 if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2749 skinframe->hasalpha = true;
2753 if (r_loadfog && skinframe->hasalpha)
2754 skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2757 R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2758 //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]);
2763 skinframe_t *R_SkinFrame_LoadMissing(void)
2765 skinframe_t *skinframe;
2767 if (cls.state == ca_dedicated)
2770 skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2771 skinframe->stain = NULL;
2772 skinframe->merged = NULL;
2773 skinframe->base = NULL;
2774 skinframe->pants = NULL;
2775 skinframe->shirt = NULL;
2776 skinframe->nmap = NULL;
2777 skinframe->gloss = NULL;
2778 skinframe->glow = NULL;
2779 skinframe->fog = NULL;
2780 skinframe->reflect = NULL;
2781 skinframe->hasalpha = false;
2783 skinframe->avgcolor[0] = rand() / RAND_MAX;
2784 skinframe->avgcolor[1] = rand() / RAND_MAX;
2785 skinframe->avgcolor[2] = rand() / RAND_MAX;
2786 skinframe->avgcolor[3] = 1;
2791 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2794 static unsigned char pix[16][16][4];
2796 if (cls.state == ca_dedicated)
2799 // this makes a light grey/dark grey checkerboard texture
2802 for (y = 0; y < 16; y++)
2804 for (x = 0; x < 16; x++)
2806 if ((y < 8) ^ (x < 8))
2824 return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, pix[0][0], 16, 16, false);
2827 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qboolean sRGB)
2829 skinframe_t *skinframe;
2830 if (cls.state == ca_dedicated)
2832 // if already loaded just return it, otherwise make a new skinframe
2833 skinframe = R_SkinFrame_Find(name, textureflags, width, height, (textureflags & TEXF_FORCE_RELOAD) ? -1 : 0, true);
2834 if (skinframe->base)
2836 textureflags &= ~TEXF_FORCE_RELOAD;
2837 skinframe->stain = NULL;
2838 skinframe->merged = NULL;
2839 skinframe->base = NULL;
2840 skinframe->pants = NULL;
2841 skinframe->shirt = NULL;
2842 skinframe->nmap = NULL;
2843 skinframe->gloss = NULL;
2844 skinframe->glow = NULL;
2845 skinframe->fog = NULL;
2846 skinframe->reflect = NULL;
2847 skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2848 // if no data was provided, then clearly the caller wanted to get a blank skinframe
2851 if (developer_loading.integer)
2852 Con_Printf("loading 32bit skin \"%s\"\n", name);
2853 skinframe->base = skinframe->merged = tex;
2854 Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2858 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2859 typedef struct suffixinfo_s
2862 qboolean flipx, flipy, flipdiagonal;
2865 static suffixinfo_t suffix[3][6] =
2868 {"px", false, false, false},
2869 {"nx", false, false, false},
2870 {"py", false, false, false},
2871 {"ny", false, false, false},
2872 {"pz", false, false, false},
2873 {"nz", false, false, false}
2876 {"posx", false, false, false},
2877 {"negx", false, false, false},
2878 {"posy", false, false, false},
2879 {"negy", false, false, false},
2880 {"posz", false, false, false},
2881 {"negz", false, false, false}
2884 {"rt", true, false, true},
2885 {"lf", false, true, true},
2886 {"ft", true, true, false},
2887 {"bk", false, false, false},
2888 {"up", true, false, true},
2889 {"dn", true, false, true}
2893 static int componentorder[4] = {0, 1, 2, 3};
2895 static rtexture_t *R_LoadCubemap(const char *basename)
2897 int i, j, cubemapsize;
2898 unsigned char *cubemappixels, *image_buffer;
2899 rtexture_t *cubemaptexture;
2901 // must start 0 so the first loadimagepixels has no requested width/height
2903 cubemappixels = NULL;
2904 cubemaptexture = NULL;
2905 // keep trying different suffix groups (posx, px, rt) until one loads
2906 for (j = 0;j < 3 && !cubemappixels;j++)
2908 // load the 6 images in the suffix group
2909 for (i = 0;i < 6;i++)
2911 // generate an image name based on the base and and suffix
2912 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2914 if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
2916 // an image loaded, make sure width and height are equal
2917 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
2919 // if this is the first image to load successfully, allocate the cubemap memory
2920 if (!cubemappixels && image_width >= 1)
2922 cubemapsize = image_width;
2923 // note this clears to black, so unavailable sides are black
2924 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2926 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2928 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);
2931 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2933 Mem_Free(image_buffer);
2937 // if a cubemap loaded, upload it
2940 if (developer_loading.integer)
2941 Con_Printf("loading cubemap \"%s\"\n", basename);
2943 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);
2944 Mem_Free(cubemappixels);
2948 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
2949 if (developer_loading.integer)
2951 Con_Printf("(tried tried images ");
2952 for (j = 0;j < 3;j++)
2953 for (i = 0;i < 6;i++)
2954 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2955 Con_Print(" and was unable to find any of them).\n");
2958 return cubemaptexture;
2961 rtexture_t *R_GetCubemap(const char *basename)
2964 for (i = 0;i < r_texture_numcubemaps;i++)
2965 if (r_texture_cubemaps[i] != NULL)
2966 if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
2967 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
2968 if (i >= MAX_CUBEMAPS || !r_main_mempool)
2969 return r_texture_whitecube;
2970 r_texture_numcubemaps++;
2971 r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
2972 strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
2973 r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
2974 return r_texture_cubemaps[i]->texture;
2977 static void R_Main_FreeViewCache(void)
2979 if (r_refdef.viewcache.entityvisible)
2980 Mem_Free(r_refdef.viewcache.entityvisible);
2981 if (r_refdef.viewcache.world_pvsbits)
2982 Mem_Free(r_refdef.viewcache.world_pvsbits);
2983 if (r_refdef.viewcache.world_leafvisible)
2984 Mem_Free(r_refdef.viewcache.world_leafvisible);
2985 if (r_refdef.viewcache.world_surfacevisible)
2986 Mem_Free(r_refdef.viewcache.world_surfacevisible);
2987 memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
2990 static void R_Main_ResizeViewCache(void)
2992 int numentities = r_refdef.scene.numentities;
2993 int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
2994 int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
2995 int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
2996 int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
2997 if (r_refdef.viewcache.maxentities < numentities)
2999 r_refdef.viewcache.maxentities = numentities;
3000 if (r_refdef.viewcache.entityvisible)
3001 Mem_Free(r_refdef.viewcache.entityvisible);
3002 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
3004 if (r_refdef.viewcache.world_numclusters != numclusters)
3006 r_refdef.viewcache.world_numclusters = numclusters;
3007 r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
3008 if (r_refdef.viewcache.world_pvsbits)
3009 Mem_Free(r_refdef.viewcache.world_pvsbits);
3010 r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
3012 if (r_refdef.viewcache.world_numleafs != numleafs)
3014 r_refdef.viewcache.world_numleafs = numleafs;
3015 if (r_refdef.viewcache.world_leafvisible)
3016 Mem_Free(r_refdef.viewcache.world_leafvisible);
3017 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
3019 if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
3021 r_refdef.viewcache.world_numsurfaces = numsurfaces;
3022 if (r_refdef.viewcache.world_surfacevisible)
3023 Mem_Free(r_refdef.viewcache.world_surfacevisible);
3024 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
3028 extern rtexture_t *loadingscreentexture;
3029 static void gl_main_start(void)
3031 loadingscreentexture = NULL;
3032 r_texture_blanknormalmap = NULL;
3033 r_texture_white = NULL;
3034 r_texture_grey128 = NULL;
3035 r_texture_black = NULL;
3036 r_texture_whitecube = NULL;
3037 r_texture_normalizationcube = NULL;
3038 r_texture_fogattenuation = NULL;
3039 r_texture_fogheighttexture = NULL;
3040 r_texture_gammaramps = NULL;
3041 r_texture_numcubemaps = 0;
3042 r_uniformbufferalignment = 32;
3044 r_loaddds = r_texture_dds_load.integer != 0;
3045 r_savedds = vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3047 switch(vid.renderpath)
3049 case RENDERPATH_GL20:
3050 case RENDERPATH_GLES2:
3051 Cvar_SetValueQuick(&r_textureunits, vid.texunits);
3052 Cvar_SetValueQuick(&gl_combine, 1);
3053 Cvar_SetValueQuick(&r_glsl, 1);
3054 r_loadnormalmap = true;
3057 #ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
3058 if (vid.support.arb_uniform_buffer_object)
3059 qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
3065 R_FrameData_Reset();
3066 R_BufferData_Reset();
3070 memset(r_queries, 0, sizeof(r_queries));
3072 r_qwskincache = NULL;
3073 r_qwskincache_size = 0;
3075 // due to caching of texture_t references, the collision cache must be reset
3076 Collision_Cache_Reset(true);
3078 // set up r_skinframe loading system for textures
3079 memset(&r_skinframe, 0, sizeof(r_skinframe));
3080 r_skinframe.loadsequence = 1;
3081 Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
3083 r_main_texturepool = R_AllocTexturePool();
3084 R_BuildBlankTextures();
3086 if (vid.support.arb_texture_cube_map)
3089 R_BuildNormalizationCube();
3091 r_texture_fogattenuation = NULL;
3092 r_texture_fogheighttexture = NULL;
3093 r_texture_gammaramps = NULL;
3094 //r_texture_fogintensity = NULL;
3095 memset(&r_fb, 0, sizeof(r_fb));
3096 Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
3097 r_glsl_permutation = NULL;
3098 memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3099 Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
3100 memset(&r_svbsp, 0, sizeof (r_svbsp));
3102 memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
3103 r_texture_numcubemaps = 0;
3105 r_refdef.fogmasktable_density = 0;
3108 // For Steelstorm Android
3109 // FIXME CACHE the program and reload
3110 // FIXME see possible combinations for SS:BR android
3111 Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
3112 R_SetupShader_SetPermutationGLSL(0, 12);
3113 R_SetupShader_SetPermutationGLSL(0, 13);
3114 R_SetupShader_SetPermutationGLSL(0, 8388621);
3115 R_SetupShader_SetPermutationGLSL(3, 0);
3116 R_SetupShader_SetPermutationGLSL(3, 2048);
3117 R_SetupShader_SetPermutationGLSL(5, 0);
3118 R_SetupShader_SetPermutationGLSL(5, 2);
3119 R_SetupShader_SetPermutationGLSL(5, 2048);
3120 R_SetupShader_SetPermutationGLSL(5, 8388608);
3121 R_SetupShader_SetPermutationGLSL(11, 1);
3122 R_SetupShader_SetPermutationGLSL(11, 2049);
3123 R_SetupShader_SetPermutationGLSL(11, 8193);
3124 R_SetupShader_SetPermutationGLSL(11, 10241);
3125 Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
3129 static void gl_main_shutdown(void)
3131 R_RenderTarget_FreeUnused(true);
3132 Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
3134 R_FrameData_Reset();
3135 R_BufferData_Reset();
3137 R_Main_FreeViewCache();
3139 switch(vid.renderpath)
3141 case RENDERPATH_GL20:
3142 case RENDERPATH_GLES2:
3143 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
3145 qglDeleteQueriesARB(r_maxqueries, r_queries);
3152 memset(r_queries, 0, sizeof(r_queries));
3154 r_qwskincache = NULL;
3155 r_qwskincache_size = 0;
3157 // clear out the r_skinframe state
3158 Mem_ExpandableArray_FreeArray(&r_skinframe.array);
3159 memset(&r_skinframe, 0, sizeof(r_skinframe));
3162 Mem_Free(r_svbsp.nodes);
3163 memset(&r_svbsp, 0, sizeof (r_svbsp));
3164 R_FreeTexturePool(&r_main_texturepool);
3165 loadingscreentexture = NULL;
3166 r_texture_blanknormalmap = NULL;
3167 r_texture_white = NULL;
3168 r_texture_grey128 = NULL;
3169 r_texture_black = NULL;
3170 r_texture_whitecube = NULL;
3171 r_texture_normalizationcube = NULL;
3172 r_texture_fogattenuation = NULL;
3173 r_texture_fogheighttexture = NULL;
3174 r_texture_gammaramps = NULL;
3175 r_texture_numcubemaps = 0;
3176 //r_texture_fogintensity = NULL;
3177 memset(&r_fb, 0, sizeof(r_fb));
3180 r_glsl_permutation = NULL;
3181 memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3182 Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
3185 static void gl_main_newmap(void)
3187 // FIXME: move this code to client
3188 char *entities, entname[MAX_QPATH];
3190 Mem_Free(r_qwskincache);
3191 r_qwskincache = NULL;
3192 r_qwskincache_size = 0;
3195 dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension);
3196 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
3198 CL_ParseEntityLump(entities);
3202 if (cl.worldmodel->brush.entities)
3203 CL_ParseEntityLump(cl.worldmodel->brush.entities);
3205 R_Main_FreeViewCache();
3207 R_FrameData_Reset();
3208 R_BufferData_Reset();
3211 void GL_Main_Init(void)
3214 r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
3215 R_InitShaderModeInfo();
3217 Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
3218 Cmd_AddCommand("r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
3219 // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
3220 if (gamemode == GAME_NEHAHRA)
3222 Cvar_RegisterVariable (&gl_fogenable);
3223 Cvar_RegisterVariable (&gl_fogdensity);
3224 Cvar_RegisterVariable (&gl_fogred);
3225 Cvar_RegisterVariable (&gl_foggreen);
3226 Cvar_RegisterVariable (&gl_fogblue);
3227 Cvar_RegisterVariable (&gl_fogstart);
3228 Cvar_RegisterVariable (&gl_fogend);
3229 Cvar_RegisterVariable (&gl_skyclip);
3231 Cvar_RegisterVariable(&r_motionblur);
3232 Cvar_RegisterVariable(&r_damageblur);
3233 Cvar_RegisterVariable(&r_motionblur_averaging);
3234 Cvar_RegisterVariable(&r_motionblur_randomize);
3235 Cvar_RegisterVariable(&r_motionblur_minblur);
3236 Cvar_RegisterVariable(&r_motionblur_maxblur);
3237 Cvar_RegisterVariable(&r_motionblur_velocityfactor);
3238 Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed);
3239 Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed);
3240 Cvar_RegisterVariable(&r_motionblur_mousefactor);
3241 Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed);
3242 Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed);
3243 Cvar_RegisterVariable(&r_equalize_entities_fullbright);
3244 Cvar_RegisterVariable(&r_equalize_entities_minambient);
3245 Cvar_RegisterVariable(&r_equalize_entities_by);
3246 Cvar_RegisterVariable(&r_equalize_entities_to);
3247 Cvar_RegisterVariable(&r_depthfirst);
3248 Cvar_RegisterVariable(&r_useinfinitefarclip);
3249 Cvar_RegisterVariable(&r_farclip_base);
3250 Cvar_RegisterVariable(&r_farclip_world);
3251 Cvar_RegisterVariable(&r_nearclip);
3252 Cvar_RegisterVariable(&r_deformvertexes);
3253 Cvar_RegisterVariable(&r_transparent);
3254 Cvar_RegisterVariable(&r_transparent_alphatocoverage);
3255 Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
3256 Cvar_RegisterVariable(&r_transparent_useplanardistance);
3257 Cvar_RegisterVariable(&r_showoverdraw);
3258 Cvar_RegisterVariable(&r_showbboxes);
3259 Cvar_RegisterVariable(&r_showbboxes_client);
3260 Cvar_RegisterVariable(&r_showsurfaces);
3261 Cvar_RegisterVariable(&r_showtris);
3262 Cvar_RegisterVariable(&r_shownormals);
3263 Cvar_RegisterVariable(&r_showlighting);
3264 Cvar_RegisterVariable(&r_showshadowvolumes);
3265 Cvar_RegisterVariable(&r_showcollisionbrushes);
3266 Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
3267 Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
3268 Cvar_RegisterVariable(&r_showdisabledepthtest);
3269 Cvar_RegisterVariable(&r_showspriteedges);
3270 Cvar_RegisterVariable(&r_showparticleedges);
3271 Cvar_RegisterVariable(&r_drawportals);
3272 Cvar_RegisterVariable(&r_drawentities);
3273 Cvar_RegisterVariable(&r_draw2d);
3274 Cvar_RegisterVariable(&r_drawworld);
3275 Cvar_RegisterVariable(&r_cullentities_trace);
3276 Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
3277 Cvar_RegisterVariable(&r_cullentities_trace_samples);
3278 Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
3279 Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
3280 Cvar_RegisterVariable(&r_cullentities_trace_expand);
3281 Cvar_RegisterVariable(&r_cullentities_trace_pad);
3282 Cvar_RegisterVariable(&r_cullentities_trace_delay);
3283 Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
3284 Cvar_RegisterVariable(&r_sortentities);
3285 Cvar_RegisterVariable(&r_drawviewmodel);
3286 Cvar_RegisterVariable(&r_drawexteriormodel);
3287 Cvar_RegisterVariable(&r_speeds);
3288 Cvar_RegisterVariable(&r_fullbrights);
3289 Cvar_RegisterVariable(&r_wateralpha);
3290 Cvar_RegisterVariable(&r_dynamic);
3291 Cvar_RegisterVariable(&r_fakelight);
3292 Cvar_RegisterVariable(&r_fakelight_intensity);
3293 Cvar_RegisterVariable(&r_fullbright_directed);
3294 Cvar_RegisterVariable(&r_fullbright_directed_ambient);
3295 Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
3296 Cvar_RegisterVariable(&r_fullbright_directed_pitch);
3297 Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
3298 Cvar_RegisterVariable(&r_fullbright);
3299 Cvar_RegisterVariable(&r_shadows);
3300 Cvar_RegisterVariable(&r_shadows_darken);
3301 Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
3302 Cvar_RegisterVariable(&r_shadows_castfrombmodels);
3303 Cvar_RegisterVariable(&r_shadows_throwdistance);
3304 Cvar_RegisterVariable(&r_shadows_throwdirection);
3305 Cvar_RegisterVariable(&r_shadows_focus);
3306 Cvar_RegisterVariable(&r_shadows_shadowmapscale);
3307 Cvar_RegisterVariable(&r_shadows_shadowmapbias);
3308 Cvar_RegisterVariable(&r_q1bsp_skymasking);
3309 Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
3310 Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
3311 Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
3312 Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
3313 Cvar_RegisterVariable(&r_fog_exp2);
3314 Cvar_RegisterVariable(&r_fog_clear);
3315 Cvar_RegisterVariable(&r_drawfog);
3316 Cvar_RegisterVariable(&r_transparentdepthmasking);
3317 Cvar_RegisterVariable(&r_transparent_sortmindist);
3318 Cvar_RegisterVariable(&r_transparent_sortmaxdist);
3319 Cvar_RegisterVariable(&r_transparent_sortarraysize);
3320 Cvar_RegisterVariable(&r_texture_dds_load);
3321 Cvar_RegisterVariable(&r_texture_dds_save);
3322 Cvar_RegisterVariable(&r_textureunits);
3323 Cvar_RegisterVariable(&gl_combine);
3324 Cvar_RegisterVariable(&r_usedepthtextures);
3325 Cvar_RegisterVariable(&r_viewfbo);
3326 Cvar_RegisterVariable(&r_rendertarget_debug);
3327 Cvar_RegisterVariable(&r_viewscale);
3328 Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3329 Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3330 Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3331 Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3332 Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3333 Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3334 Cvar_RegisterVariable(&r_glsl);
3335 Cvar_RegisterVariable(&r_glsl_deluxemapping);
3336 Cvar_RegisterVariable(&r_glsl_offsetmapping);
3337 Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3338 Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3339 Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3340 Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3341 Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3342 Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3343 Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3344 Cvar_RegisterVariable(&r_glsl_postprocess);
3345 Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3346 Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3347 Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3348 Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3349 Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3350 Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3351 Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3352 Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3353 Cvar_RegisterVariable(&r_celshading);
3354 Cvar_RegisterVariable(&r_celoutlines);
3356 Cvar_RegisterVariable(&r_water);
3357 Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3358 Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3359 Cvar_RegisterVariable(&r_water_clippingplanebias);
3360 Cvar_RegisterVariable(&r_water_refractdistort);
3361 Cvar_RegisterVariable(&r_water_reflectdistort);
3362 Cvar_RegisterVariable(&r_water_scissormode);
3363 Cvar_RegisterVariable(&r_water_lowquality);
3364 Cvar_RegisterVariable(&r_water_hideplayer);
3366 Cvar_RegisterVariable(&r_lerpsprites);
3367 Cvar_RegisterVariable(&r_lerpmodels);
3368 Cvar_RegisterVariable(&r_lerplightstyles);
3369 Cvar_RegisterVariable(&r_waterscroll);
3370 Cvar_RegisterVariable(&r_bloom);
3371 Cvar_RegisterVariable(&r_bloom_colorscale);
3372 Cvar_RegisterVariable(&r_bloom_brighten);
3373 Cvar_RegisterVariable(&r_bloom_blur);
3374 Cvar_RegisterVariable(&r_bloom_resolution);
3375 Cvar_RegisterVariable(&r_bloom_colorexponent);
3376 Cvar_RegisterVariable(&r_bloom_colorsubtract);
3377 Cvar_RegisterVariable(&r_bloom_scenebrightness);
3378 Cvar_RegisterVariable(&r_hdr_scenebrightness);
3379 Cvar_RegisterVariable(&r_hdr_glowintensity);
3380 Cvar_RegisterVariable(&r_hdr_irisadaptation);
3381 Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3382 Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3383 Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3384 Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3385 Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3386 Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3387 Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3388 Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3389 Cvar_RegisterVariable(&developer_texturelogging);
3390 Cvar_RegisterVariable(&gl_lightmaps);
3391 Cvar_RegisterVariable(&r_test);
3392 Cvar_RegisterVariable(&r_batch_multidraw);
3393 Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3394 Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3395 Cvar_RegisterVariable(&r_glsl_skeletal);
3396 Cvar_RegisterVariable(&r_glsl_saturation);
3397 Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3398 Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3399 Cvar_RegisterVariable(&r_framedatasize);
3400 for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3401 Cvar_RegisterVariable(&r_buffermegs[i]);
3402 Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3403 if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3404 Cvar_SetValue("r_fullbrights", 0);
3405 #ifdef DP_MOBILETOUCH
3406 // GLES devices have terrible depth precision in general, so...
3407 Cvar_SetValueQuick(&r_nearclip, 4);
3408 Cvar_SetValueQuick(&r_farclip_base, 4096);
3409 Cvar_SetValueQuick(&r_farclip_world, 0);
3410 Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3412 R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3415 void Render_Init(void)
3428 R_LightningBeams_Init();
3438 extern char *ENGINE_EXTENSIONS;
3441 gl_renderer = (const char *)qglGetString(GL_RENDERER);
3442 gl_vendor = (const char *)qglGetString(GL_VENDOR);
3443 gl_version = (const char *)qglGetString(GL_VERSION);
3444 gl_extensions = (const char *)qglGetString(GL_EXTENSIONS);
3448 if (!gl_platformextensions)
3449 gl_platformextensions = "";
3451 Con_Printf("GL_VENDOR: %s\n", gl_vendor);
3452 Con_Printf("GL_RENDERER: %s\n", gl_renderer);
3453 Con_Printf("GL_VERSION: %s\n", gl_version);
3454 Con_DPrintf("GL_EXTENSIONS: %s\n", gl_extensions);
3455 Con_DPrintf("%s_EXTENSIONS: %s\n", gl_platform, gl_platformextensions);
3457 VID_CheckExtensions();
3459 // LordHavoc: report supported extensions
3461 Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions );
3463 Con_DPrintf("\nQuakeC extensions for server and client: %s\n", vm_sv_extensions );
3466 // clear to black (loading plaque will be seen over this)
3467 GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128);
3471 int R_CullBox(const vec3_t mins, const vec3_t maxs)
3475 if (r_trippy.integer)
3477 for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
3479 p = r_refdef.view.frustum + i;
3484 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3488 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3492 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3496 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3500 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3504 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3508 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3512 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3520 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3524 if (r_trippy.integer)
3526 for (i = 0;i < numplanes;i++)
3533 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3537 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3541 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3545 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3549 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3553 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3557 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3561 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3569 //==================================================================================
3571 // LordHavoc: this stores temporary data used within the same frame
3573 typedef struct r_framedata_mem_s
3575 struct r_framedata_mem_s *purge; // older mem block to free on next frame
3576 size_t size; // how much usable space
3577 size_t current; // how much space in use
3578 size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3579 size_t wantedsize; // how much space was allocated
3580 unsigned char *data; // start of real data (16byte aligned)
3584 static r_framedata_mem_t *r_framedata_mem;
3586 void R_FrameData_Reset(void)
3588 while (r_framedata_mem)
3590 r_framedata_mem_t *next = r_framedata_mem->purge;
3591 Mem_Free(r_framedata_mem);
3592 r_framedata_mem = next;
3596 static void R_FrameData_Resize(qboolean mustgrow)
3599 wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3600 wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3601 if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3603 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3604 newmem->wantedsize = wantedsize;
3605 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3606 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3607 newmem->current = 0;
3609 newmem->purge = r_framedata_mem;
3610 r_framedata_mem = newmem;
3614 void R_FrameData_NewFrame(void)
3616 R_FrameData_Resize(false);
3617 if (!r_framedata_mem)
3619 // if we ran out of space on the last frame, free the old memory now
3620 while (r_framedata_mem->purge)
3622 // repeatedly remove the second item in the list, leaving only head
3623 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3624 Mem_Free(r_framedata_mem->purge);
3625 r_framedata_mem->purge = next;
3627 // reset the current mem pointer
3628 r_framedata_mem->current = 0;
3629 r_framedata_mem->mark = 0;
3632 void *R_FrameData_Alloc(size_t size)
3637 // align to 16 byte boundary - the data pointer is already aligned, so we
3638 // only need to ensure the size of every allocation is also aligned
3639 size = (size + 15) & ~15;
3641 while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3643 // emergency - we ran out of space, allocate more memory
3644 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3645 newvalue = r_framedatasize.value * 2.0f;
3646 // 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
3647 if (sizeof(size_t) >= 8)
3648 newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3650 newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3651 // this might not be a growing it, but we'll allocate another buffer every time
3652 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3653 R_FrameData_Resize(true);
3656 data = r_framedata_mem->data + r_framedata_mem->current;
3657 r_framedata_mem->current += size;
3659 // count the usage for stats
3660 r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3661 r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3663 return (void *)data;
3666 void *R_FrameData_Store(size_t size, void *data)
3668 void *d = R_FrameData_Alloc(size);
3670 memcpy(d, data, size);
3674 void R_FrameData_SetMark(void)
3676 if (!r_framedata_mem)
3678 r_framedata_mem->mark = r_framedata_mem->current;
3681 void R_FrameData_ReturnToMark(void)
3683 if (!r_framedata_mem)
3685 r_framedata_mem->current = r_framedata_mem->mark;
3688 //==================================================================================
3690 // avoid reusing the same buffer objects on consecutive frames
3691 #define R_BUFFERDATA_CYCLE 3
3693 typedef struct r_bufferdata_buffer_s
3695 struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3696 size_t size; // how much usable space
3697 size_t current; // how much space in use
3698 r_meshbuffer_t *buffer; // the buffer itself
3700 r_bufferdata_buffer_t;
3702 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3703 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3705 /// frees all dynamic buffers
3706 void R_BufferData_Reset(void)
3709 r_bufferdata_buffer_t **p, *mem;
3710 for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3712 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3715 p = &r_bufferdata_buffer[cycle][type];
3721 R_Mesh_DestroyMeshBuffer(mem->buffer);
3728 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3729 static void R_BufferData_Resize(r_bufferdata_type_t type, qboolean mustgrow, size_t minsize)
3731 r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3733 float newvalue = r_buffermegs[type].value;
3735 // increase the cvar if we have to (but only if we already have a mem)
3736 if (mustgrow && mem)
3738 newvalue = bound(0.25f, newvalue, 256.0f);
3739 while (newvalue * 1024*1024 < minsize)
3742 // clamp the cvar to valid range
3743 newvalue = bound(0.25f, newvalue, 256.0f);
3744 if (r_buffermegs[type].value != newvalue)
3745 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3747 // calculate size in bytes
3748 size = (size_t)(newvalue * 1024*1024);
3749 size = bound(131072, size, 256*1024*1024);
3751 // allocate a new buffer if the size is different (purge old one later)
3752 // or if we were told we must grow the buffer
3753 if (!mem || mem->size != size || mustgrow)
3755 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3758 if (type == R_BUFFERDATA_VERTEX)
3759 mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3760 else if (type == R_BUFFERDATA_INDEX16)
3761 mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3762 else if (type == R_BUFFERDATA_INDEX32)
3763 mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3764 else if (type == R_BUFFERDATA_UNIFORM)
3765 mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3766 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3767 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3771 void R_BufferData_NewFrame(void)
3774 r_bufferdata_buffer_t **p, *mem;
3775 // cycle to the next frame's buffers
3776 r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3777 // if we ran out of space on the last time we used these buffers, free the old memory now
3778 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3780 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3782 R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3783 // free all but the head buffer, this is how we recycle obsolete
3784 // buffers after they are no longer in use
3785 p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3791 R_Mesh_DestroyMeshBuffer(mem->buffer);
3794 // reset the current offset
3795 r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3800 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3802 r_bufferdata_buffer_t *mem;
3806 *returnbufferoffset = 0;
3808 // align size to a byte boundary appropriate for the buffer type, this
3809 // makes all allocations have aligned start offsets
3810 if (type == R_BUFFERDATA_UNIFORM)
3811 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3813 padsize = (datasize + 15) & ~15;
3815 // if we ran out of space in this buffer we must allocate a new one
3816 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)
3817 R_BufferData_Resize(type, true, padsize);
3819 // if the resize did not give us enough memory, fail
3820 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)
3821 Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3823 mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3824 offset = (int)mem->current;
3825 mem->current += padsize;
3827 // upload the data to the buffer at the chosen offset
3829 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3830 R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3832 // count the usage for stats
3833 r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3834 r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3836 // return the buffer offset
3837 *returnbufferoffset = offset;
3842 //==================================================================================
3844 // LordHavoc: animcache originally written by Echon, rewritten since then
3847 * Animation cache prevents re-generating mesh data for an animated model
3848 * multiple times in one frame for lighting, shadowing, reflections, etc.
3851 void R_AnimCache_Free(void)
3855 void R_AnimCache_ClearCache(void)
3858 entity_render_t *ent;
3860 for (i = 0;i < r_refdef.scene.numentities;i++)
3862 ent = r_refdef.scene.entities[i];
3863 ent->animcache_vertex3f = NULL;
3864 ent->animcache_vertex3f_vertexbuffer = NULL;
3865 ent->animcache_vertex3f_bufferoffset = 0;
3866 ent->animcache_normal3f = NULL;
3867 ent->animcache_normal3f_vertexbuffer = NULL;
3868 ent->animcache_normal3f_bufferoffset = 0;
3869 ent->animcache_svector3f = NULL;
3870 ent->animcache_svector3f_vertexbuffer = NULL;
3871 ent->animcache_svector3f_bufferoffset = 0;
3872 ent->animcache_tvector3f = NULL;
3873 ent->animcache_tvector3f_vertexbuffer = NULL;
3874 ent->animcache_tvector3f_bufferoffset = 0;
3875 ent->animcache_vertexmesh = NULL;
3876 ent->animcache_vertexmesh_vertexbuffer = NULL;
3877 ent->animcache_vertexmesh_bufferoffset = 0;
3878 ent->animcache_skeletaltransform3x4 = NULL;
3879 ent->animcache_skeletaltransform3x4buffer = NULL;
3880 ent->animcache_skeletaltransform3x4offset = 0;
3881 ent->animcache_skeletaltransform3x4size = 0;
3885 static void R_AnimCache_UpdateEntityMeshBuffers(entity_render_t *ent, int numvertices)
3889 // check if we need the meshbuffers
3890 if (!vid.useinterleavedarrays)
3893 if (!ent->animcache_vertexmesh && ent->animcache_normal3f)
3894 ent->animcache_vertexmesh = (r_vertexmesh_t *)R_FrameData_Alloc(sizeof(r_vertexmesh_t)*numvertices);
3895 // TODO: upload vertexbuffer?
3896 if (ent->animcache_vertexmesh)
3898 r_refdef.stats[r_stat_animcache_vertexmesh_count] += 1;
3899 r_refdef.stats[r_stat_animcache_vertexmesh_vertices] += numvertices;
3900 r_refdef.stats[r_stat_animcache_vertexmesh_maxvertices] = max(r_refdef.stats[r_stat_animcache_vertexmesh_maxvertices], numvertices);
3901 memcpy(ent->animcache_vertexmesh, ent->model->surfmesh.data_vertexmesh, sizeof(r_vertexmesh_t)*numvertices);
3902 for (i = 0;i < numvertices;i++)
3903 memcpy(ent->animcache_vertexmesh[i].vertex3f, ent->animcache_vertex3f + 3*i, sizeof(float[3]));
3904 if (ent->animcache_svector3f)
3905 for (i = 0;i < numvertices;i++)
3906 memcpy(ent->animcache_vertexmesh[i].svector3f, ent->animcache_svector3f + 3*i, sizeof(float[3]));
3907 if (ent->animcache_tvector3f)
3908 for (i = 0;i < numvertices;i++)
3909 memcpy(ent->animcache_vertexmesh[i].tvector3f, ent->animcache_tvector3f + 3*i, sizeof(float[3]));
3910 if (ent->animcache_normal3f)
3911 for (i = 0;i < numvertices;i++)
3912 memcpy(ent->animcache_vertexmesh[i].normal3f, ent->animcache_normal3f + 3*i, sizeof(float[3]));
3916 qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
3918 dp_model_t *model = ent->model;
3921 // see if this ent is worth caching
3922 if (!model || !model->Draw || !model->AnimateVertices)
3924 // nothing to cache if it contains no animations and has no skeleton
3925 if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3927 // see if it is already cached for gpuskeletal
3928 if (ent->animcache_skeletaltransform3x4)
3930 // see if it is already cached as a mesh
3931 if (ent->animcache_vertex3f)
3933 // check if we need to add normals or tangents
3934 if (ent->animcache_normal3f)
3935 wantnormals = false;
3936 if (ent->animcache_svector3f)
3937 wanttangents = false;
3938 if (!wantnormals && !wanttangents)
3942 // check which kind of cache we need to generate
3943 if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3945 // cache the skeleton so the vertex shader can use it
3946 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3947 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3948 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3949 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3950 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4);
3951 // note: this can fail if the buffer is at the grow limit
3952 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3953 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3955 else if (ent->animcache_vertex3f)
3957 // mesh was already cached but we may need to add normals/tangents
3958 // (this only happens with multiple views, reflections, cameras, etc)
3959 if (wantnormals || wanttangents)
3961 numvertices = model->surfmesh.num_vertices;
3963 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3966 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3967 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3969 model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3970 R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices);
3971 r_refdef.stats[r_stat_animcache_shade_count] += 1;
3972 r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3973 r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3978 // generate mesh cache
3979 numvertices = model->surfmesh.num_vertices;
3980 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3982 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3985 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3986 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3988 model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
3989 R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices);
3990 if (wantnormals || wanttangents)
3992 r_refdef.stats[r_stat_animcache_shade_count] += 1;
3993 r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3994 r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3996 r_refdef.stats[r_stat_animcache_shape_count] += 1;
3997 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
3998 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
4003 void R_AnimCache_CacheVisibleEntities(void)
4007 // TODO: thread this
4008 // NOTE: R_PrepareRTLights() also caches entities
4010 for (i = 0;i < r_refdef.scene.numentities;i++)
4011 if (r_refdef.viewcache.entityvisible[i])
4012 R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
4015 //==================================================================================
4017 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)
4020 vec3_t eyemins, eyemaxs;
4021 vec3_t boxmins, boxmaxs;
4022 vec3_t padmins, padmaxs;
4025 dp_model_t *model = r_refdef.scene.worldmodel;
4026 static vec3_t positions[] = {
4027 { 0.5f, 0.5f, 0.5f },
4028 { 0.0f, 0.0f, 0.0f },
4029 { 0.0f, 0.0f, 1.0f },
4030 { 0.0f, 1.0f, 0.0f },
4031 { 0.0f, 1.0f, 1.0f },
4032 { 1.0f, 0.0f, 0.0f },
4033 { 1.0f, 0.0f, 1.0f },
4034 { 1.0f, 1.0f, 0.0f },
4035 { 1.0f, 1.0f, 1.0f },
4038 // sample count can be set to -1 to skip this logic, for flicker-prone objects
4042 // view origin is not used for culling in portal/reflection/refraction renders or isometric views
4043 if (!r_refdef.view.usevieworiginculling)
4046 if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
4049 // expand the eye box a little
4050 eyemins[0] = eye[0] - eyejitter;
4051 eyemaxs[0] = eye[0] + eyejitter;
4052 eyemins[1] = eye[1] - eyejitter;
4053 eyemaxs[1] = eye[1] + eyejitter;
4054 eyemins[2] = eye[2] - eyejitter;
4055 eyemaxs[2] = eye[2] + eyejitter;
4056 // expand the box a little
4057 boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
4058 boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
4059 boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
4060 boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
4061 boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
4062 boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
4063 // make an even larger box for the acceptable area
4064 padmins[0] = boxmins[0] - pad;
4065 padmaxs[0] = boxmaxs[0] + pad;
4066 padmins[1] = boxmins[1] - pad;
4067 padmaxs[1] = boxmaxs[1] + pad;
4068 padmins[2] = boxmins[2] - pad;
4069 padmaxs[2] = boxmaxs[2] + pad;
4071 // return true if eye overlaps enlarged box
4072 if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
4075 // try specific positions in the box first - note that these can be cached
4076 if (r_cullentities_trace_entityocclusion.integer)
4078 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
4080 VectorCopy(eye, start);
4081 end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
4082 end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
4083 end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
4084 //trace_t trace = CL_TraceLine(start, end, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, 0.0f, true, false, NULL, true, true);
4085 trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
4086 // not picky - if the trace ended anywhere in the box we're good
4087 if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4091 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4094 // try various random positions
4095 for (i = 0; i < numsamples; i++)
4097 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
4098 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
4099 if (r_cullentities_trace_entityocclusion.integer)
4101 trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
4102 // not picky - if the trace ended anywhere in the box we're good
4103 if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4106 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4114 static void R_View_UpdateEntityVisible (void)
4119 entity_render_t *ent;
4121 if (r_refdef.envmap || r_fb.water.hideplayer)
4122 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
4123 else if (chase_active.integer || r_fb.water.renderingscene)
4124 renderimask = RENDER_VIEWMODEL;
4126 renderimask = RENDER_EXTERIORMODEL;
4127 if (!r_drawviewmodel.integer)
4128 renderimask |= RENDER_VIEWMODEL;
4129 if (!r_drawexteriormodel.integer)
4130 renderimask |= RENDER_EXTERIORMODEL;
4131 memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4132 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4134 // worldmodel can check visibility
4135 for (i = 0;i < r_refdef.scene.numentities;i++)
4137 ent = r_refdef.scene.entities[i];
4138 if (!(ent->flags & renderimask))
4139 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)))
4140 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))
4141 r_refdef.viewcache.entityvisible[i] = true;
4146 // no worldmodel or it can't check visibility
4147 for (i = 0;i < r_refdef.scene.numentities;i++)
4149 ent = r_refdef.scene.entities[i];
4150 if (!(ent->flags & renderimask))
4151 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)))
4152 r_refdef.viewcache.entityvisible[i] = true;
4155 if (r_cullentities_trace.integer)
4157 for (i = 0;i < r_refdef.scene.numentities;i++)
4159 if (!r_refdef.viewcache.entityvisible[i])
4161 ent = r_refdef.scene.entities[i];
4162 if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4164 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4165 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))
4166 ent->last_trace_visibility = realtime;
4167 if (ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
4168 r_refdef.viewcache.entityvisible[i] = 0;
4174 /// only used if skyrendermasked, and normally returns false
4175 static int R_DrawBrushModelsSky (void)
4178 entity_render_t *ent;
4181 for (i = 0;i < r_refdef.scene.numentities;i++)
4183 if (!r_refdef.viewcache.entityvisible[i])
4185 ent = r_refdef.scene.entities[i];
4186 if (!ent->model || !ent->model->DrawSky)
4188 ent->model->DrawSky(ent);
4194 static void R_DrawNoModel(entity_render_t *ent);
4195 static void R_DrawModels(void)
4198 entity_render_t *ent;
4200 for (i = 0;i < r_refdef.scene.numentities;i++)
4202 if (!r_refdef.viewcache.entityvisible[i])
4204 ent = r_refdef.scene.entities[i];
4205 r_refdef.stats[r_stat_entities]++;
4207 if (ent->model && !strncmp(ent->model->name, "models/proto_", 13))
4210 Matrix4x4_ToVectors(&ent->matrix, f, l, u, o);
4211 Con_Printf("R_DrawModels\n");
4212 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]);
4213 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);
4214 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);
4217 if (ent->model && ent->model->Draw != NULL)
4218 ent->model->Draw(ent);
4224 static void R_DrawModelsDepth(void)
4227 entity_render_t *ent;
4229 for (i = 0;i < r_refdef.scene.numentities;i++)
4231 if (!r_refdef.viewcache.entityvisible[i])
4233 ent = r_refdef.scene.entities[i];
4234 if (ent->model && ent->model->DrawDepth != NULL)
4235 ent->model->DrawDepth(ent);
4239 static void R_DrawModelsDebug(void)
4242 entity_render_t *ent;
4244 for (i = 0;i < r_refdef.scene.numentities;i++)
4246 if (!r_refdef.viewcache.entityvisible[i])
4248 ent = r_refdef.scene.entities[i];
4249 if (ent->model && ent->model->DrawDebug != NULL)
4250 ent->model->DrawDebug(ent);
4254 static void R_DrawModelsAddWaterPlanes(void)
4257 entity_render_t *ent;
4259 for (i = 0;i < r_refdef.scene.numentities;i++)
4261 if (!r_refdef.viewcache.entityvisible[i])
4263 ent = r_refdef.scene.entities[i];
4264 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4265 ent->model->DrawAddWaterPlanes(ent);
4269 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}};
4271 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4273 if (r_hdr_irisadaptation.integer)
4278 vec3_t diffusenormal;
4280 vec_t brightness = 0.0f;
4285 VectorCopy(r_refdef.view.forward, forward);
4286 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4288 p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4289 p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4290 p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4291 R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4292 d = DotProduct(forward, diffusenormal);
4293 brightness += VectorLength(ambient);
4295 brightness += d * VectorLength(diffuse);
4297 brightness *= 1.0f / c;
4298 brightness += 0.00001f; // make sure it's never zero
4299 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4300 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4301 current = r_hdr_irisadaptation_value.value;
4303 current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4304 else if (current > goal)
4305 current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4306 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4307 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4309 else if (r_hdr_irisadaptation_value.value != 1.0f)
4310 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4313 static void R_View_SetFrustum(const int *scissor)
4316 double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4317 vec3_t forward, left, up, origin, v;
4321 // flipped x coordinates (because x points left here)
4322 fpx = 1.0 - 2.0 * (scissor[0] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4323 fnx = 1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4324 // non-flipped y coordinates
4325 fny = -1.0 + 2.0 * (scissor[1] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4326 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4329 // we can't trust r_refdef.view.forward and friends in reflected scenes
4330 Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4333 r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4334 r_refdef.view.frustum[0].normal[1] = 0 - 0;
4335 r_refdef.view.frustum[0].normal[2] = -1 - 0;
4336 r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4337 r_refdef.view.frustum[1].normal[1] = 0 + 0;
4338 r_refdef.view.frustum[1].normal[2] = -1 + 0;
4339 r_refdef.view.frustum[2].normal[0] = 0 - 0;
4340 r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4341 r_refdef.view.frustum[2].normal[2] = -1 - 0;
4342 r_refdef.view.frustum[3].normal[0] = 0 + 0;
4343 r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4344 r_refdef.view.frustum[3].normal[2] = -1 + 0;
4348 zNear = r_refdef.nearclip;
4349 nudge = 1.0 - 1.0 / (1<<23);
4350 r_refdef.view.frustum[4].normal[0] = 0 - 0;
4351 r_refdef.view.frustum[4].normal[1] = 0 - 0;
4352 r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4353 r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4354 r_refdef.view.frustum[5].normal[0] = 0 + 0;
4355 r_refdef.view.frustum[5].normal[1] = 0 + 0;
4356 r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4357 r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4363 r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4364 r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4365 r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4366 r_refdef.view.frustum[0].dist = m[15] - m[12];
4368 r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4369 r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4370 r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4371 r_refdef.view.frustum[1].dist = m[15] + m[12];
4373 r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4374 r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4375 r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4376 r_refdef.view.frustum[2].dist = m[15] - m[13];
4378 r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4379 r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4380 r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4381 r_refdef.view.frustum[3].dist = m[15] + m[13];
4383 r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4384 r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4385 r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4386 r_refdef.view.frustum[4].dist = m[15] - m[14];
4388 r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4389 r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4390 r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4391 r_refdef.view.frustum[5].dist = m[15] + m[14];
4394 if (r_refdef.view.useperspective)
4396 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4397 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]);
4398 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]);
4399 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]);
4400 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]);
4402 // then the normals from the corners relative to origin
4403 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4404 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4405 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4406 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4408 // in a NORMAL view, forward cross left == up
4409 // in a REFLECTED view, forward cross left == down
4410 // so our cross products above need to be adjusted for a left handed coordinate system
4411 CrossProduct(forward, left, v);
4412 if(DotProduct(v, up) < 0)
4414 VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4415 VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4416 VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4417 VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4420 // Leaving those out was a mistake, those were in the old code, and they
4421 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4422 // I couldn't reproduce it after adding those normalizations. --blub
4423 VectorNormalize(r_refdef.view.frustum[0].normal);
4424 VectorNormalize(r_refdef.view.frustum[1].normal);
4425 VectorNormalize(r_refdef.view.frustum[2].normal);
4426 VectorNormalize(r_refdef.view.frustum[3].normal);
4428 // make the corners absolute
4429 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4430 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4431 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4432 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4435 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4437 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4438 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4439 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4440 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4441 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4445 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4446 VectorScale(left, 1.0f, r_refdef.view.frustum[1].normal);
4447 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4448 VectorScale(up, 1.0f, r_refdef.view.frustum[3].normal);
4449 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4450 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4451 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4452 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4453 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4454 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4456 r_refdef.view.numfrustumplanes = 5;
4458 if (r_refdef.view.useclipplane)
4460 r_refdef.view.numfrustumplanes = 6;
4461 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4464 for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4465 PlaneClassify(r_refdef.view.frustum + i);
4467 // LordHavoc: note to all quake engine coders, Quake had a special case
4468 // for 90 degrees which assumed a square view (wrong), so I removed it,
4469 // Quake2 has it disabled as well.
4471 // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4472 //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4473 //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4474 //PlaneClassify(&frustum[0]);
4476 // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4477 //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4478 //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4479 //PlaneClassify(&frustum[1]);
4481 // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4482 //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4483 //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4484 //PlaneClassify(&frustum[2]);
4486 // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4487 //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4488 //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4489 //PlaneClassify(&frustum[3]);
4492 //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4493 //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4494 //PlaneClassify(&frustum[4]);
4497 static void R_View_UpdateWithScissor(const int *myscissor)
4499 R_Main_ResizeViewCache();
4500 R_View_SetFrustum(myscissor);
4501 R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4502 R_View_UpdateEntityVisible();
4505 static void R_View_Update(void)
4507 R_Main_ResizeViewCache();
4508 R_View_SetFrustum(NULL);
4509 R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4510 R_View_UpdateEntityVisible();
4513 float viewscalefpsadjusted = 1.0f;
4515 static void R_GetScaledViewSize(int width, int height, int *outwidth, int *outheight)
4517 float scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
4518 scale = bound(0.03125f, scale, 1.0f);
4519 *outwidth = (int)ceil(width * scale);
4520 *outheight = (int)ceil(height * scale);
4523 void R_SetupView(qboolean allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4525 const float *customclipplane = NULL;
4527 int /*rtwidth,*/ rtheight;
4528 if (r_refdef.view.useclipplane && allowwaterclippingplane)
4530 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4531 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4532 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4533 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4534 dist = r_refdef.view.clipplane.dist;
4535 plane[0] = r_refdef.view.clipplane.normal[0];
4536 plane[1] = r_refdef.view.clipplane.normal[1];
4537 plane[2] = r_refdef.view.clipplane.normal[2];
4541 //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
4542 rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
4544 if (!r_refdef.view.useperspective)
4545 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);
4546 else if (vid.stencil && r_useinfinitefarclip.integer)
4547 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);
4549 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);
4550 R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4551 R_SetViewport(&r_refdef.view.viewport);
4554 void R_EntityMatrix(const matrix4x4_t *matrix)
4556 if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4558 gl_modelmatrixchanged = false;
4559 gl_modelmatrix = *matrix;
4560 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4561 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4562 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4563 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4565 switch(vid.renderpath)
4567 case RENDERPATH_GL20:
4568 case RENDERPATH_GLES2:
4569 if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4570 if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4576 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4578 r_viewport_t viewport;
4582 // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
4583 R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4584 R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4585 R_SetViewport(&viewport);
4586 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4587 GL_Color(1, 1, 1, 1);
4588 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4589 GL_BlendFunc(GL_ONE, GL_ZERO);
4590 GL_ScissorTest(false);
4591 GL_DepthMask(false);
4592 GL_DepthRange(0, 1);
4593 GL_DepthTest(false);
4594 GL_DepthFunc(GL_LEQUAL);
4595 R_EntityMatrix(&identitymatrix);
4596 R_Mesh_ResetTextureState();
4597 GL_PolygonOffset(0, 0);
4598 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
4599 switch(vid.renderpath)
4601 case RENDERPATH_GL20:
4602 case RENDERPATH_GLES2:
4603 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4606 GL_CullFace(GL_NONE);
4611 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4613 R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4616 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4618 R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4619 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4620 GL_Color(1, 1, 1, 1);
4621 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4622 GL_BlendFunc(GL_ONE, GL_ZERO);
4623 GL_ScissorTest(true);
4625 GL_DepthRange(0, 1);
4627 GL_DepthFunc(GL_LEQUAL);
4628 R_EntityMatrix(&identitymatrix);
4629 R_Mesh_ResetTextureState();
4630 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4631 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
4632 switch(vid.renderpath)
4634 case RENDERPATH_GL20:
4635 case RENDERPATH_GLES2:
4636 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4639 GL_CullFace(r_refdef.view.cullface_back);
4644 R_RenderView_UpdateViewVectors
4647 void R_RenderView_UpdateViewVectors(void)
4649 // break apart the view matrix into vectors for various purposes
4650 // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4651 // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4652 Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4653 VectorNegate(r_refdef.view.left, r_refdef.view.right);
4654 // make an inverted copy of the view matrix for tracking sprites
4655 Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4658 void R_RenderTarget_FreeUnused(qboolean force)
4661 end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
4662 for (i = 0; i < end; i++)
4664 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4665 // free resources for rendertargets that have not been used for a while
4666 // (note: this check is run after the frame render, so any targets used
4667 // this frame will not be affected even at low framerates)
4668 if (r && (realtime - r->lastusetime > 0.2 || force))
4671 R_Mesh_DestroyFramebufferObject(r->fbo);
4672 for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4673 if (r->colortexture[j])
4674 R_FreeTexture(r->colortexture[j]);
4675 if (r->depthtexture)
4676 R_FreeTexture(r->depthtexture);
4677 Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4682 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4684 float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4688 y2 = (th - y - h) * ih;
4699 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)
4702 r_rendertarget_t *r = NULL;
4704 // first try to reuse an existing slot if possible
4705 end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
4706 for (i = 0; i < end; i++)
4708 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4709 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)
4714 // no unused exact match found, so we have to make one in the first unused slot
4715 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4716 r->texturewidth = texturewidth;
4717 r->textureheight = textureheight;
4718 r->colortextype[0] = colortextype0;
4719 r->colortextype[1] = colortextype1;
4720 r->colortextype[2] = colortextype2;
4721 r->colortextype[3] = colortextype3;
4722 r->depthtextype = depthtextype;
4723 r->depthisrenderbuffer = depthisrenderbuffer;
4724 for (j = 0; j < 4; j++)
4725 if (r->colortextype[j])
4726 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);
4727 if (r->depthtextype)
4729 if (r->depthisrenderbuffer)
4730 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);
4732 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);
4734 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4736 r_refdef.stats[r_stat_rendertargets_used]++;
4737 r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4738 r->lastusetime = realtime;
4739 R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4743 static void R_Water_StartFrame(void)
4745 int waterwidth, waterheight;
4747 if (vid.width > (int)vid.maxtexturesize_2d || vid.height > (int)vid.maxtexturesize_2d)
4750 // set waterwidth and waterheight to the water resolution that will be
4751 // used (often less than the screen resolution for faster rendering)
4752 waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width);
4753 waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height);
4754 R_GetScaledViewSize(waterwidth, waterheight, &waterwidth, &waterheight);
4756 if (!r_water.integer || r_showsurfaces.integer)
4757 waterwidth = waterheight = 0;
4759 // set up variables that will be used in shader setup
4760 r_fb.water.waterwidth = waterwidth;
4761 r_fb.water.waterheight = waterheight;
4762 r_fb.water.texturewidth = waterwidth;
4763 r_fb.water.textureheight = waterheight;
4764 r_fb.water.camerawidth = waterwidth;
4765 r_fb.water.cameraheight = waterheight;
4766 r_fb.water.screenscale[0] = 0.5f;
4767 r_fb.water.screenscale[1] = 0.5f;
4768 r_fb.water.screencenter[0] = 0.5f;
4769 r_fb.water.screencenter[1] = 0.5f;
4770 r_fb.water.enabled = waterwidth != 0;
4772 r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4773 r_fb.water.numwaterplanes = 0;
4776 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4778 int planeindex, bestplaneindex, vertexindex;
4779 vec3_t mins, maxs, normal, center, v, n;
4780 vec_t planescore, bestplanescore;
4782 r_waterstate_waterplane_t *p;
4783 texture_t *t = R_GetCurrentTexture(surface->texture);
4785 rsurface.texture = t;
4786 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4787 // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4788 if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4790 // average the vertex normals, find the surface bounds (after deformvertexes)
4791 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4792 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4793 VectorCopy(n, normal);
4794 VectorCopy(v, mins);
4795 VectorCopy(v, maxs);
4796 for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4798 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4799 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4800 VectorAdd(normal, n, normal);
4801 mins[0] = min(mins[0], v[0]);
4802 mins[1] = min(mins[1], v[1]);
4803 mins[2] = min(mins[2], v[2]);
4804 maxs[0] = max(maxs[0], v[0]);
4805 maxs[1] = max(maxs[1], v[1]);
4806 maxs[2] = max(maxs[2], v[2]);
4808 VectorNormalize(normal);
4809 VectorMAM(0.5f, mins, 0.5f, maxs, center);
4811 VectorCopy(normal, plane.normal);
4812 VectorNormalize(plane.normal);
4813 plane.dist = DotProduct(center, plane.normal);
4814 PlaneClassify(&plane);
4815 if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4817 // skip backfaces (except if nocullface is set)
4818 // if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4820 VectorNegate(plane.normal, plane.normal);
4822 PlaneClassify(&plane);
4826 // find a matching plane if there is one
4827 bestplaneindex = -1;
4828 bestplanescore = 1048576.0f;
4829 for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4831 if(p->camera_entity == t->camera_entity)
4833 planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4834 if (bestplaneindex < 0 || bestplanescore > planescore)
4836 bestplaneindex = planeindex;
4837 bestplanescore = planescore;
4841 planeindex = bestplaneindex;
4843 // if this surface does not fit any known plane rendered this frame, add one
4844 if (planeindex < 0 || bestplanescore > 0.001f)
4846 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4848 // store the new plane
4849 planeindex = r_fb.water.numwaterplanes++;
4850 p = r_fb.water.waterplanes + planeindex;
4852 // clear materialflags and pvs
4853 p->materialflags = 0;
4854 p->pvsvalid = false;
4855 p->camera_entity = t->camera_entity;
4856 VectorCopy(mins, p->mins);
4857 VectorCopy(maxs, p->maxs);
4861 // We're totally screwed.
4867 // merge mins/maxs when we're adding this surface to the plane
4868 p = r_fb.water.waterplanes + planeindex;
4869 p->mins[0] = min(p->mins[0], mins[0]);
4870 p->mins[1] = min(p->mins[1], mins[1]);
4871 p->mins[2] = min(p->mins[2], mins[2]);
4872 p->maxs[0] = max(p->maxs[0], maxs[0]);
4873 p->maxs[1] = max(p->maxs[1], maxs[1]);
4874 p->maxs[2] = max(p->maxs[2], maxs[2]);
4876 // merge this surface's materialflags into the waterplane
4877 p->materialflags |= t->currentmaterialflags;
4878 if(!(p->materialflags & MATERIALFLAG_CAMERA))
4880 // merge this surface's PVS into the waterplane
4881 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4882 && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4884 r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4890 extern cvar_t r_drawparticles;
4891 extern cvar_t r_drawdecals;
4893 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4896 r_refdef_view_t originalview;
4897 r_refdef_view_t myview;
4898 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;
4899 r_waterstate_waterplane_t *p;
4901 r_rendertarget_t *rt;
4903 originalview = r_refdef.view;
4905 // lowquality hack, temporarily shut down some cvars and restore afterwards
4906 qualityreduction = r_water_lowquality.integer;
4907 if (qualityreduction > 0)
4909 if (qualityreduction >= 1)
4911 old_r_shadows = r_shadows.integer;
4912 old_r_worldrtlight = r_shadow_realtime_world.integer;
4913 old_r_dlight = r_shadow_realtime_dlight.integer;
4914 Cvar_SetValueQuick(&r_shadows, 0);
4915 Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4916 Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4918 if (qualityreduction >= 2)
4920 old_r_dynamic = r_dynamic.integer;
4921 old_r_particles = r_drawparticles.integer;
4922 old_r_decals = r_drawdecals.integer;
4923 Cvar_SetValueQuick(&r_dynamic, 0);
4924 Cvar_SetValueQuick(&r_drawparticles, 0);
4925 Cvar_SetValueQuick(&r_drawdecals, 0);
4929 for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4931 p->rt_reflection = NULL;
4932 p->rt_refraction = NULL;
4933 p->rt_camera = NULL;
4937 r_refdef.view = originalview;
4938 r_refdef.view.showdebug = false;
4939 r_refdef.view.width = r_fb.water.waterwidth;
4940 r_refdef.view.height = r_fb.water.waterheight;
4941 r_refdef.view.useclipplane = true;
4942 myview = r_refdef.view;
4943 r_fb.water.renderingscene = true;
4944 for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4946 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4949 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4951 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);
4952 if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4954 r_refdef.view = myview;
4955 Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4956 Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4957 if(r_water_scissormode.integer)
4959 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4960 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4962 p->rt_reflection = NULL;
4963 p->rt_refraction = NULL;
4964 p->rt_camera = NULL;
4969 r_refdef.view.clipplane = p->plane;
4970 // reflected view origin may be in solid, so don't cull with it
4971 r_refdef.view.usevieworiginculling = false;
4972 // reverse the cullface settings for this render
4973 r_refdef.view.cullface_front = GL_FRONT;
4974 r_refdef.view.cullface_back = GL_BACK;
4975 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4977 r_refdef.view.usecustompvs = true;
4979 memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4981 memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4984 r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4985 R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4986 GL_ScissorTest(false);
4987 R_ClearScreen(r_refdef.fogenabled);
4988 GL_ScissorTest(true);
4989 if(r_water_scissormode.integer & 2)
4990 R_View_UpdateWithScissor(myscissor);
4993 R_AnimCache_CacheVisibleEntities();
4994 if(r_water_scissormode.integer & 1)
4995 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4996 R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4998 r_fb.water.hideplayer = false;
4999 p->rt_reflection = rt;
5002 // render the normal view scene and copy into texture
5003 // (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)
5004 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
5006 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);
5007 if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5009 r_refdef.view = myview;
5010 if(r_water_scissormode.integer)
5012 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
5013 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
5015 p->rt_reflection = NULL;
5016 p->rt_refraction = NULL;
5017 p->rt_camera = NULL;
5022 r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
5024 r_refdef.view.clipplane = p->plane;
5025 VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5026 r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5028 if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
5030 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5031 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
5032 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5033 R_RenderView_UpdateViewVectors();
5034 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5036 r_refdef.view.usecustompvs = true;
5037 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);
5041 PlaneClassify(&r_refdef.view.clipplane);
5043 R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5044 GL_ScissorTest(false);
5045 R_ClearScreen(r_refdef.fogenabled);
5046 GL_ScissorTest(true);
5047 if(r_water_scissormode.integer & 2)
5048 R_View_UpdateWithScissor(myscissor);
5051 R_AnimCache_CacheVisibleEntities();
5052 if(r_water_scissormode.integer & 1)
5053 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
5054 R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5056 r_fb.water.hideplayer = false;
5057 p->rt_refraction = rt;
5059 else if (p->materialflags & MATERIALFLAG_CAMERA)
5061 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);
5062 if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5064 r_refdef.view = myview;
5066 r_refdef.view.clipplane = p->plane;
5067 VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5068 r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5070 r_refdef.view.width = r_fb.water.camerawidth;
5071 r_refdef.view.height = r_fb.water.cameraheight;
5072 r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
5073 r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
5074 r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
5075 r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
5077 if(p->camera_entity)
5079 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5080 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5083 // note: all of the view is used for displaying... so
5084 // there is no use in scissoring
5086 // reverse the cullface settings for this render
5087 r_refdef.view.cullface_front = GL_FRONT;
5088 r_refdef.view.cullface_back = GL_BACK;
5089 // also reverse the view matrix
5090 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
5091 R_RenderView_UpdateViewVectors();
5092 if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5094 r_refdef.view.usecustompvs = true;
5095 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);
5098 // camera needs no clipplane
5099 r_refdef.view.useclipplane = false;
5100 // TODO: is the camera origin always valid? if so we don't need to clear this
5101 r_refdef.view.usevieworiginculling = false;
5103 PlaneClassify(&r_refdef.view.clipplane);
5105 r_fb.water.hideplayer = false;
5107 R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5108 GL_ScissorTest(false);
5109 R_ClearScreen(r_refdef.fogenabled);
5110 GL_ScissorTest(true);
5112 R_AnimCache_CacheVisibleEntities();
5113 R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5115 r_fb.water.hideplayer = false;
5120 r_fb.water.renderingscene = false;
5121 r_refdef.view = originalview;
5122 R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5124 R_AnimCache_CacheVisibleEntities();
5127 r_refdef.view = originalview;
5128 r_fb.water.renderingscene = false;
5129 Cvar_SetValueQuick(&r_water, 0);
5130 Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed! Turned off r_water.\n");
5132 // lowquality hack, restore cvars
5133 if (qualityreduction > 0)
5135 if (qualityreduction >= 1)
5137 Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5138 Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5139 Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5141 if (qualityreduction >= 2)
5143 Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5144 Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5145 Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5150 static void R_Bloom_StartFrame(void)
5152 int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
5153 int viewwidth, viewheight;
5154 textype_t textype = TEXTYPE_COLORBUFFER;
5156 // clear the pointers to rendertargets from last frame as they're stale
5157 r_fb.rt_screen = NULL;
5158 r_fb.rt_bloom = NULL;
5160 switch (vid.renderpath)
5162 case RENDERPATH_GL20:
5163 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5164 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5165 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5166 // for simplicity, bloom requires FBO render to texture, which basically all video drivers support now
5167 if (!vid.support.ext_framebuffer_object)
5170 case RENDERPATH_GLES2:
5171 r_fb.usedepthtextures = false;
5175 if (r_viewscale_fpsscaling.integer)
5177 double actualframetime;
5178 double targetframetime;
5180 actualframetime = r_refdef.lastdrawscreentime;
5181 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5182 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5183 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5184 if (r_viewscale_fpsscaling_stepsize.value > 0)
5185 adjust = (int)(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5186 viewscalefpsadjusted += adjust;
5187 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5190 viewscalefpsadjusted = 1.0f;
5192 R_GetScaledViewSize(r_refdef.view.width, r_refdef.view.height, &viewwidth, &viewheight);
5194 // set bloomwidth and bloomheight to the bloom resolution that will be
5195 // used (often less than the screen resolution for faster rendering)
5196 r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, vid.width);
5197 r_fb.bloomheight = r_fb.bloomwidth * vid.height / vid.width;
5198 r_fb.bloomheight = bound(1, r_fb.bloomheight, vid.height);
5199 r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5200 r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5202 // calculate desired texture sizes
5203 screentexturewidth = viewwidth;
5204 screentextureheight = viewheight;
5205 bloomtexturewidth = r_fb.bloomwidth;
5206 bloomtextureheight = r_fb.bloomheight;
5208 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))
5210 Cvar_SetValueQuick(&r_bloom, 0);
5211 Cvar_SetValueQuick(&r_motionblur, 0);
5212 Cvar_SetValueQuick(&r_damageblur, 0);
5215 // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5216 if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5218 if (r_fb.ghosttexture)
5219 R_FreeTexture(r_fb.ghosttexture);
5220 r_fb.ghosttexture = NULL;
5222 r_fb.screentexturewidth = screentexturewidth;
5223 r_fb.screentextureheight = screentextureheight;
5224 r_fb.textype = textype;
5226 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5228 if (r_motionblur.value > 0 || r_damageblur.value > 0)
5229 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);
5230 r_fb.ghosttexture_valid = false;
5234 if (r_bloom.integer)
5236 // bloom texture is a different resolution
5237 r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.width);
5238 r_fb.bloomheight = r_fb.bloomwidth * r_refdef.view.height / r_refdef.view.width;
5239 r_fb.bloomheight = bound(1, r_fb.bloomheight, r_refdef.view.height);
5242 r_fb.bloomwidth = r_fb.bloomheight = 0;
5244 r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5246 r_refdef.view.clear = true;
5249 static void R_Bloom_MakeTexture(void)
5252 float xoffset, yoffset, r, brighten;
5253 float colorscale = r_bloom_colorscale.value;
5254 r_viewport_t bloomviewport;
5255 r_rendertarget_t *prev, *cur;
5256 textype_t textype = r_fb.rt_screen->colortextype[0];
5258 r_refdef.stats[r_stat_bloom]++;
5260 R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5262 // scale down screen texture to the bloom texture size
5264 prev = r_fb.rt_screen;
5265 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5266 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5267 R_SetViewport(&bloomviewport);
5268 GL_CullFace(GL_NONE);
5269 GL_DepthTest(false);
5270 GL_BlendFunc(GL_ONE, GL_ZERO);
5271 GL_Color(colorscale, colorscale, colorscale, 1);
5272 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5273 // TODO: do boxfilter scale-down in shader?
5274 R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, true);
5275 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5276 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5277 // we now have a properly scaled bloom image
5279 // multiply bloom image by itself as many times as desired to darken it
5280 // TODO: if people actually use this it could be done more quickly in the previous shader pass
5281 for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5284 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5285 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5287 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5289 GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128);
5290 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5291 GL_Color(1,1,1,1); // no fix factor supported here
5292 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5293 R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, false);
5294 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5295 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5298 range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5299 brighten = r_bloom_brighten.value;
5300 brighten = sqrt(brighten);
5302 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5304 for (dir = 0;dir < 2;dir++)
5307 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5308 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5309 // blend on at multiple vertical offsets to achieve a vertical blur
5310 // TODO: do offset blends using GLSL
5311 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5312 GL_BlendFunc(GL_ONE, GL_ZERO);
5313 R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, false);
5314 for (x = -range;x <= range;x++)
5316 if (!dir){xoffset = 0;yoffset = x;}
5317 else {xoffset = x;yoffset = 0;}
5318 xoffset /= (float)prev->texturewidth;
5319 yoffset /= (float)prev->textureheight;
5320 // compute a texcoord array with the specified x and y offset
5321 r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5322 r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5323 r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5324 r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5325 r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5326 r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5327 r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5328 r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5329 // this r value looks like a 'dot' particle, fading sharply to
5330 // black at the edges
5331 // (probably not realistic but looks good enough)
5332 //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5333 //r = brighten/(range*2+1);
5334 r = brighten / (range * 2 + 1);
5336 r *= (1 - x*x/(float)((range+1)*(range+1)));
5339 GL_Color(r, r, r, 1);
5340 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5341 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5342 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5343 GL_BlendFunc(GL_ONE, GL_ONE);
5347 // now we have the bloom image, so keep track of it
5348 r_fb.rt_bloom = cur;
5351 static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5353 dpuint64 permutation;
5354 float uservecs[4][4];
5355 rtexture_t *viewtexture;
5356 rtexture_t *bloomtexture;
5358 R_EntityMatrix(&identitymatrix);
5360 if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
5362 // declare variables
5363 float blur_factor, blur_mouseaccel, blur_velocity;
5364 static float blur_average;
5365 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5367 // set a goal for the factoring
5368 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value)
5369 / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5370 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value)
5371 / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5372 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value)
5373 + (blur_mouseaccel * r_motionblur_mousefactor.value));
5375 // from the goal, pick an averaged value between goal and last value
5376 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5377 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5379 // enforce minimum amount of blur
5380 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5382 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5384 // calculate values into a standard alpha
5385 cl.motionbluralpha = 1 - exp(-
5387 (r_motionblur.value * blur_factor / 80)
5389 (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5392 max(0.0001, cl.time - cl.oldtime) // fps independent
5395 // randomization for the blur value to combat persistent ghosting
5396 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5397 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5400 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5401 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5403 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5404 GL_Color(1, 1, 1, cl.motionbluralpha);
5405 R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5406 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5407 R_SetupShader_Generic(r_fb.ghosttexture, NULL, GL_MODULATE, 1, false, true, true);
5408 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5409 r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5412 // updates old view angles for next pass
5413 VectorCopy(cl.viewangles, blur_oldangles);
5415 // copy view into the ghost texture
5416 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5417 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5418 r_fb.ghosttexture_valid = true;
5421 if (r_fb.bloomwidth)
5423 // make the bloom texture
5424 R_Bloom_MakeTexture();
5427 #if _MSC_VER >= 1400
5428 #define sscanf sscanf_s
5430 memset(uservecs, 0, sizeof(uservecs));
5431 if (r_glsl_postprocess_uservec1_enable.integer)
5432 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5433 if (r_glsl_postprocess_uservec2_enable.integer)
5434 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5435 if (r_glsl_postprocess_uservec3_enable.integer)
5436 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5437 if (r_glsl_postprocess_uservec4_enable.integer)
5438 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5440 // render to the screen fbo
5441 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5442 GL_Color(1, 1, 1, 1);
5443 GL_BlendFunc(GL_ONE, GL_ZERO);
5445 viewtexture = r_fb.rt_screen->colortexture[0];
5446 bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5448 if (r_rendertarget_debug.integer >= 0)
5450 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5451 if (rt && rt->colortexture[0])
5453 viewtexture = rt->colortexture[0];
5454 bloomtexture = NULL;
5458 R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5459 switch(vid.renderpath)
5461 case RENDERPATH_GL20:
5462 case RENDERPATH_GLES2:
5464 (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5465 | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5466 | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5467 | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5468 | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5469 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5470 if (r_glsl_permutation->tex_Texture_First >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , viewtexture);
5471 if (r_glsl_permutation->tex_Texture_Second >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second , bloomtexture);
5472 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps );
5473 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]);
5474 if (r_glsl_permutation->loc_PixelSize >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5475 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]);
5476 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]);
5477 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]);
5478 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]);
5479 if (r_glsl_permutation->loc_Saturation >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation , r_glsl_saturation.value);
5480 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
5481 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);
5484 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5485 r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5488 matrix4x4_t r_waterscrollmatrix;
5490 void R_UpdateFog(void)
5493 if (gamemode == GAME_NEHAHRA)
5495 if (gl_fogenable.integer)
5497 r_refdef.oldgl_fogenable = true;
5498 r_refdef.fog_density = gl_fogdensity.value;
5499 r_refdef.fog_red = gl_fogred.value;
5500 r_refdef.fog_green = gl_foggreen.value;
5501 r_refdef.fog_blue = gl_fogblue.value;
5502 r_refdef.fog_alpha = 1;
5503 r_refdef.fog_start = 0;
5504 r_refdef.fog_end = gl_skyclip.value;
5505 r_refdef.fog_height = 1<<30;
5506 r_refdef.fog_fadedepth = 128;
5508 else if (r_refdef.oldgl_fogenable)
5510 r_refdef.oldgl_fogenable = false;
5511 r_refdef.fog_density = 0;
5512 r_refdef.fog_red = 0;
5513 r_refdef.fog_green = 0;
5514 r_refdef.fog_blue = 0;
5515 r_refdef.fog_alpha = 0;
5516 r_refdef.fog_start = 0;
5517 r_refdef.fog_end = 0;
5518 r_refdef.fog_height = 1<<30;
5519 r_refdef.fog_fadedepth = 128;
5524 r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5525 r_refdef.fog_start = max(0, r_refdef.fog_start);
5526 r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5528 if (r_refdef.fog_density && r_drawfog.integer)
5530 r_refdef.fogenabled = true;
5531 // this is the point where the fog reaches 0.9986 alpha, which we
5532 // consider a good enough cutoff point for the texture
5533 // (0.9986 * 256 == 255.6)
5534 if (r_fog_exp2.integer)
5535 r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5537 r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5538 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5539 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5540 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5541 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5542 R_BuildFogHeightTexture();
5543 // fog color was already set
5544 // update the fog texture
5545 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)
5546 R_BuildFogTexture();
5547 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5548 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5551 r_refdef.fogenabled = false;
5554 if (r_refdef.fog_density)
5556 r_refdef.fogcolor[0] = r_refdef.fog_red;
5557 r_refdef.fogcolor[1] = r_refdef.fog_green;
5558 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5560 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5561 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5562 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5563 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5567 VectorCopy(r_refdef.fogcolor, fogvec);
5568 // color.rgb *= ContrastBoost * SceneBrightness;
5569 VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5570 r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5571 r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5572 r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5577 void R_UpdateVariables(void)
5581 r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5583 r_refdef.farclip = r_farclip_base.value;
5584 if (r_refdef.scene.worldmodel)
5585 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5586 r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5588 if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5589 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5590 r_refdef.polygonfactor = 0;
5591 r_refdef.polygonoffset = 0;
5592 r_refdef.shadowpolygonfactor = r_refdef.polygonfactor + r_shadow_polygonfactor.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
5593 r_refdef.shadowpolygonoffset = r_refdef.polygonoffset + r_shadow_polygonoffset.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
5595 r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5596 r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5597 r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5598 r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5599 r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5600 if (FAKELIGHT_ENABLED)
5602 r_refdef.scene.lightmapintensity *= r_fakelight_intensity.value;
5604 else if (r_refdef.scene.worldmodel)
5606 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5608 if (r_showsurfaces.integer)
5610 r_refdef.scene.rtworld = false;
5611 r_refdef.scene.rtworldshadows = false;
5612 r_refdef.scene.rtdlight = false;
5613 r_refdef.scene.rtdlightshadows = false;
5614 r_refdef.scene.lightmapintensity = 0;
5617 r_gpuskeletal = false;
5618 switch(vid.renderpath)
5620 case RENDERPATH_GL20:
5621 r_gpuskeletal = vid.support.arb_uniform_buffer_object && r_glsl_skeletal.integer && !r_showsurfaces.integer; // FIXME add r_showsurfaces support to GLSL skeletal!
5622 case RENDERPATH_GLES2:
5623 if(!vid_gammatables_trivial)
5625 if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5627 // build GLSL gamma texture
5628 #define RAMPWIDTH 256
5629 unsigned short ramp[RAMPWIDTH * 3];
5630 unsigned char rampbgr[RAMPWIDTH][4];
5633 r_texture_gammaramps_serial = vid_gammatables_serial;
5635 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5636 for(i = 0; i < RAMPWIDTH; ++i)
5638 rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5639 rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5640 rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5643 if (r_texture_gammaramps)
5645 R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1);
5649 r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5655 // remove GLSL gamma texture
5661 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5662 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5668 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5669 if( scenetype != r_currentscenetype ) {
5670 // store the old scenetype
5671 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5672 r_currentscenetype = scenetype;
5673 // move in the new scene
5674 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5683 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5685 // of course, we could also add a qboolean that provides a lock state and a ReleaseScenePointer function..
5686 if( scenetype == r_currentscenetype ) {
5687 return &r_refdef.scene;
5689 return &r_scenes_store[ scenetype ];
5693 static int R_SortEntities_Compare(const void *ap, const void *bp)
5695 const entity_render_t *a = *(const entity_render_t **)ap;
5696 const entity_render_t *b = *(const entity_render_t **)bp;
5699 if(a->model < b->model)
5701 if(a->model > b->model)
5705 // TODO possibly calculate the REAL skinnum here first using
5707 if(a->skinnum < b->skinnum)
5709 if(a->skinnum > b->skinnum)
5712 // everything we compared is equal
5715 static void R_SortEntities(void)
5717 // below or equal 2 ents, sorting never gains anything
5718 if(r_refdef.scene.numentities <= 2)
5721 qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5729 extern cvar_t r_shadow_bouncegrid;
5730 extern cvar_t v_isometric;
5731 extern void V_MakeViewIsometric(void);
5732 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5734 matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5736 rtexture_t *viewdepthtexture = NULL;
5737 rtexture_t *viewcolortexture = NULL;
5738 int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5740 // finish any 2D rendering that was queued
5743 if (r_timereport_active)
5744 R_TimeReport("start");
5745 r_textureframe++; // used only by R_GetCurrentTexture
5746 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5748 if(R_CompileShader_CheckStaticParms())
5751 if (!r_drawentities.integer)
5752 r_refdef.scene.numentities = 0;
5753 else if (r_sortentities.integer)
5756 R_AnimCache_ClearCache();
5758 /* adjust for stereo display */
5759 if(R_Stereo_Active())
5761 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);
5762 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5765 if (r_refdef.view.isoverlay)
5767 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5768 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5769 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5770 R_TimeReport("depthclear");
5772 r_refdef.view.showdebug = false;
5774 r_fb.water.enabled = false;
5775 r_fb.water.numwaterplanes = 0;
5777 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5779 r_refdef.view.matrix = originalmatrix;
5785 if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5787 r_refdef.view.matrix = originalmatrix;
5791 r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5792 if (v_isometric.integer && r_refdef.view.ismain)
5793 V_MakeViewIsometric();
5795 r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5797 if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5798 // in sRGB fallback, behave similar to true sRGB: convert this
5799 // value from linear to sRGB
5800 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5802 R_RenderView_UpdateViewVectors();
5804 R_Shadow_UpdateWorldLightSelection();
5806 // this will set up r_fb.rt_screen
5807 R_Bloom_StartFrame();
5809 // apply bloom brightness offset
5811 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5813 // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5816 viewfbo = r_fb.rt_screen->fbo;
5817 viewdepthtexture = r_fb.rt_screen->depthtexture;
5818 viewcolortexture = r_fb.rt_screen->colortexture[0];
5822 viewheight = height;
5825 R_Water_StartFrame();
5828 if (r_timereport_active)
5829 R_TimeReport("viewsetup");
5831 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5833 // clear the whole fbo every frame - otherwise the driver will consider
5834 // it to be an inter-frame texture and stall in multi-gpu configurations
5836 GL_ScissorTest(false);
5837 R_ClearScreen(r_refdef.fogenabled);
5838 if (r_timereport_active)
5839 R_TimeReport("viewclear");
5841 r_refdef.view.clear = true;
5843 r_refdef.view.showdebug = true;
5846 if (r_timereport_active)
5847 R_TimeReport("visibility");
5849 R_AnimCache_CacheVisibleEntities();
5850 if (r_timereport_active)
5851 R_TimeReport("animcache");
5853 R_Shadow_UpdateBounceGridTexture();
5854 if (r_timereport_active && r_shadow_bouncegrid.integer)
5855 R_TimeReport("bouncegrid");
5857 r_fb.water.numwaterplanes = 0;
5858 if (r_fb.water.enabled)
5859 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5861 // for the actual view render we use scissoring a fair amount, so scissor
5862 // test needs to be on
5864 GL_ScissorTest(true);
5865 GL_Scissor(viewx, viewy, viewwidth, viewheight);
5866 R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5867 r_fb.water.numwaterplanes = 0;
5869 // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5870 GL_ScissorTest(false);
5872 R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
5873 if (r_timereport_active)
5874 R_TimeReport("blendview");
5876 r_refdef.view.matrix = originalmatrix;
5880 // go back to 2d rendering
5884 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5886 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5888 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5889 if (r_timereport_active)
5890 R_TimeReport("waterworld");
5893 // don't let sound skip if going slow
5894 if (r_refdef.scene.extraupdate)
5897 R_DrawModelsAddWaterPlanes();
5898 if (r_timereport_active)
5899 R_TimeReport("watermodels");
5901 if (r_fb.water.numwaterplanes)
5903 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5904 if (r_timereport_active)
5905 R_TimeReport("waterscenes");
5909 extern cvar_t cl_locs_show;
5910 static void R_DrawLocs(void);
5911 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5912 static void R_DrawModelDecals(void);
5913 extern cvar_t cl_decals_newsystem;
5914 extern qboolean r_shadow_usingdeferredprepass;
5915 extern int r_shadow_shadowmapatlas_modelshadows_size;
5916 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5918 qboolean shadowmapping = false;
5920 if (r_timereport_active)
5921 R_TimeReport("beginscene");
5923 r_refdef.stats[r_stat_renders]++;
5927 // don't let sound skip if going slow
5928 if (r_refdef.scene.extraupdate)
5931 R_MeshQueue_BeginScene();
5935 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);
5937 if (r_timereport_active)
5938 R_TimeReport("skystartframe");
5940 if (cl.csqc_vidvars.drawworld)
5942 // don't let sound skip if going slow
5943 if (r_refdef.scene.extraupdate)
5946 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5948 r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5949 if (r_timereport_active)
5950 R_TimeReport("worldsky");
5953 if (R_DrawBrushModelsSky() && r_timereport_active)
5954 R_TimeReport("bmodelsky");
5956 if (skyrendermasked && skyrenderlater)
5958 // we have to force off the water clipping plane while rendering sky
5959 R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5961 R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5962 if (r_timereport_active)
5963 R_TimeReport("sky");
5967 // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5968 r_shadow_viewfbo = viewfbo;
5969 r_shadow_viewdepthtexture = viewdepthtexture;
5970 r_shadow_viewcolortexture = viewcolortexture;
5971 r_shadow_viewx = viewx;
5972 r_shadow_viewy = viewy;
5973 r_shadow_viewwidth = viewwidth;
5974 r_shadow_viewheight = viewheight;
5976 R_Shadow_PrepareModelShadows();
5977 R_Shadow_PrepareLights();
5978 if (r_timereport_active)
5979 R_TimeReport("preparelights");
5981 // render all the shadowmaps that will be used for this view
5982 shadowmapping = R_Shadow_ShadowMappingEnabled();
5983 if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
5985 R_Shadow_DrawShadowMaps();
5986 if (r_timereport_active)
5987 R_TimeReport("shadowmaps");
5990 // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
5991 if (r_shadow_usingdeferredprepass)
5992 R_Shadow_DrawPrepass();
5994 // now we begin the forward pass of the view render
5995 if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
5997 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
5998 if (r_timereport_active)
5999 R_TimeReport("worlddepth");
6001 if (r_depthfirst.integer >= 2)
6003 R_DrawModelsDepth();
6004 if (r_timereport_active)
6005 R_TimeReport("modeldepth");
6008 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
6010 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
6011 if (r_timereport_active)
6012 R_TimeReport("world");
6015 // don't let sound skip if going slow
6016 if (r_refdef.scene.extraupdate)
6020 if (r_timereport_active)
6021 R_TimeReport("models");
6023 // don't let sound skip if going slow
6024 if (r_refdef.scene.extraupdate)
6027 if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && !r_shadows_drawafterrtlighting.integer && r_refdef.scene.lightmapintensity > 0)
6029 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6030 R_Shadow_DrawModelShadows();
6031 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6032 // don't let sound skip if going slow
6033 if (r_refdef.scene.extraupdate)
6037 if (!r_shadow_usingdeferredprepass)
6039 R_Shadow_DrawLights();
6040 if (r_timereport_active)
6041 R_TimeReport("rtlights");
6044 // don't let sound skip if going slow
6045 if (r_refdef.scene.extraupdate)
6048 if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && r_shadows_drawafterrtlighting.integer && r_refdef.scene.lightmapintensity > 0)
6050 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6051 R_Shadow_DrawModelShadows();
6052 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6053 // don't let sound skip if going slow
6054 if (r_refdef.scene.extraupdate)
6058 if (cl.csqc_vidvars.drawworld)
6060 if (cl_decals_newsystem.integer)
6062 R_DrawModelDecals();
6063 if (r_timereport_active)
6064 R_TimeReport("modeldecals");
6069 if (r_timereport_active)
6070 R_TimeReport("decals");
6074 if (r_timereport_active)
6075 R_TimeReport("particles");
6078 if (r_timereport_active)
6079 R_TimeReport("explosions");
6082 if (r_refdef.view.showdebug)
6084 if (cl_locs_show.integer)
6087 if (r_timereport_active)
6088 R_TimeReport("showlocs");
6091 if (r_drawportals.integer)
6094 if (r_timereport_active)
6095 R_TimeReport("portals");
6098 if (r_showbboxes_client.value > 0)
6100 R_DrawEntityBBoxes(CLVM_prog);
6101 if (r_timereport_active)
6102 R_TimeReport("clbboxes");
6104 if (r_showbboxes.value > 0)
6106 R_DrawEntityBBoxes(SVVM_prog);
6107 if (r_timereport_active)
6108 R_TimeReport("svbboxes");
6112 if (r_transparent.integer)
6114 R_MeshQueue_RenderTransparent();
6115 if (r_timereport_active)
6116 R_TimeReport("drawtrans");
6119 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))
6121 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
6122 if (r_timereport_active)
6123 R_TimeReport("worlddebug");
6124 R_DrawModelsDebug();
6125 if (r_timereport_active)
6126 R_TimeReport("modeldebug");
6129 if (cl.csqc_vidvars.drawworld)
6131 R_Shadow_DrawCoronas();
6132 if (r_timereport_active)
6133 R_TimeReport("coronas");
6136 // don't let sound skip if going slow
6137 if (r_refdef.scene.extraupdate)
6141 static const unsigned short bboxelements[36] =
6151 #define BBOXEDGES 13
6152 static const float bboxedges[BBOXEDGES][6] =
6155 { 0, 0, 0, 1, 1, 1 },
6157 { 0, 0, 0, 0, 1, 0 },
6158 { 0, 0, 0, 1, 0, 0 },
6159 { 0, 1, 0, 1, 1, 0 },
6160 { 1, 0, 0, 1, 1, 0 },
6162 { 0, 0, 1, 0, 1, 1 },
6163 { 0, 0, 1, 1, 0, 1 },
6164 { 0, 1, 1, 1, 1, 1 },
6165 { 1, 0, 1, 1, 1, 1 },
6167 { 0, 0, 0, 0, 0, 1 },
6168 { 1, 0, 0, 1, 0, 1 },
6169 { 0, 1, 0, 0, 1, 1 },
6170 { 1, 1, 0, 1, 1, 1 },
6173 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6175 int numvertices = BBOXEDGES * 8;
6176 float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6177 int numtriangles = BBOXEDGES * 12;
6178 unsigned short elements[BBOXEDGES * 36];
6180 float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6182 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6184 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6185 GL_DepthMask(false);
6186 GL_DepthRange(0, 1);
6187 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6189 for (edge = 0; edge < BBOXEDGES; edge++)
6191 for (i = 0; i < 3; i++)
6193 edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6194 edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6196 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6197 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6198 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6199 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6200 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6201 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6202 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6203 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6204 for (i = 0; i < 36; i++)
6205 elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6207 R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6208 if (r_refdef.fogenabled)
6210 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6212 f1 = RSurf_FogVertex(v);
6214 c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6215 c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6216 c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6219 R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6220 R_Mesh_ResetTextureState();
6221 R_SetupShader_Generic_NoTexture(false, false);
6222 R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6225 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6227 // hacky overloading of the parameters
6228 prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6231 prvm_edict_t *edict;
6233 GL_CullFace(GL_NONE);
6234 R_SetupShader_Generic_NoTexture(false, false);
6236 for (i = 0;i < numsurfaces;i++)
6238 edict = PRVM_EDICT_NUM(surfacelist[i]);
6239 switch ((int)PRVM_serveredictfloat(edict, solid))
6241 case SOLID_NOT: Vector4Set(color, 1, 1, 1, 0.05);break;
6242 case SOLID_TRIGGER: Vector4Set(color, 1, 0, 1, 0.10);break;
6243 case SOLID_BBOX: Vector4Set(color, 0, 1, 0, 0.10);break;
6244 case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6245 case SOLID_BSP: Vector4Set(color, 0, 0, 1, 0.05);break;
6246 case SOLID_CORPSE: Vector4Set(color, 1, 0.5, 0, 0.05);break;
6247 default: Vector4Set(color, 0, 0, 0, 0.50);break;
6249 if (prog == CLVM_prog)
6250 color[3] *= r_showbboxes_client.value;
6252 color[3] *= r_showbboxes.value;
6253 color[3] = bound(0, color[3], 1);
6254 GL_DepthTest(!r_showdisabledepthtest.integer);
6255 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6259 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6262 prvm_edict_t *edict;
6268 for (i = 0; i < prog->num_edicts; i++)
6270 edict = PRVM_EDICT_NUM(i);
6271 if (edict->priv.server->free)
6273 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6274 if (PRVM_serveredictedict(edict, tag_entity) != 0)
6276 if (PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6278 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6279 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6283 static const int nomodelelement3i[24] =
6295 static const unsigned short nomodelelement3s[24] =
6307 static const float nomodelvertex3f[6*3] =
6317 static const float nomodelcolor4f[6*4] =
6319 0.0f, 0.0f, 0.5f, 1.0f,
6320 0.0f, 0.0f, 0.5f, 1.0f,
6321 0.0f, 0.5f, 0.0f, 1.0f,
6322 0.0f, 0.5f, 0.0f, 1.0f,
6323 0.5f, 0.0f, 0.0f, 1.0f,
6324 0.5f, 0.0f, 0.0f, 1.0f
6327 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6333 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);
6335 // this is only called once per entity so numsurfaces is always 1, and
6336 // surfacelist is always {0}, so this code does not handle batches
6338 if (rsurface.ent_flags & RENDER_ADDITIVE)
6340 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6341 GL_DepthMask(false);
6343 else if (ent->alpha < 1)
6345 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6346 GL_DepthMask(false);
6350 GL_BlendFunc(GL_ONE, GL_ZERO);
6353 GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6354 GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6355 GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6356 GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6357 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6358 for (i = 0, c = color4f;i < 6;i++, c += 4)
6360 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6361 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6362 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6365 if (r_refdef.fogenabled)
6367 for (i = 0, c = color4f;i < 6;i++, c += 4)
6369 f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6371 c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6372 c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6373 c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6376 // R_Mesh_ResetTextureState();
6377 R_SetupShader_Generic_NoTexture(false, false);
6378 R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6379 R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6382 void R_DrawNoModel(entity_render_t *ent)
6385 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6386 if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6387 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6389 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6392 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6394 vec3_t right1, right2, diff, normal;
6396 VectorSubtract (org2, org1, normal);
6398 // calculate 'right' vector for start
6399 VectorSubtract (r_refdef.view.origin, org1, diff);
6400 CrossProduct (normal, diff, right1);
6401 VectorNormalize (right1);
6403 // calculate 'right' vector for end
6404 VectorSubtract (r_refdef.view.origin, org2, diff);
6405 CrossProduct (normal, diff, right2);
6406 VectorNormalize (right2);
6408 vert[ 0] = org1[0] + width * right1[0];
6409 vert[ 1] = org1[1] + width * right1[1];
6410 vert[ 2] = org1[2] + width * right1[2];
6411 vert[ 3] = org1[0] - width * right1[0];
6412 vert[ 4] = org1[1] - width * right1[1];
6413 vert[ 5] = org1[2] - width * right1[2];
6414 vert[ 6] = org2[0] - width * right2[0];
6415 vert[ 7] = org2[1] - width * right2[1];
6416 vert[ 8] = org2[2] - width * right2[2];
6417 vert[ 9] = org2[0] + width * right2[0];
6418 vert[10] = org2[1] + width * right2[1];
6419 vert[11] = org2[2] + width * right2[2];
6422 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)
6424 vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6425 vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6426 vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6427 vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6428 vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6429 vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6430 vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6431 vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6432 vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6433 vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6434 vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6435 vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6438 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6443 VectorSet(v, x, y, z);
6444 for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6445 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6447 if (i == mesh->numvertices)
6449 if (mesh->numvertices < mesh->maxvertices)
6451 VectorCopy(v, vertex3f);
6452 mesh->numvertices++;
6454 return mesh->numvertices;
6460 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6464 element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6465 element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6466 e = mesh->element3i + mesh->numtriangles * 3;
6467 for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6469 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6470 if (mesh->numtriangles < mesh->maxtriangles)
6475 mesh->numtriangles++;
6477 element[1] = element[2];
6481 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6485 element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6486 element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6487 e = mesh->element3i + mesh->numtriangles * 3;
6488 for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6490 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6491 if (mesh->numtriangles < mesh->maxtriangles)
6496 mesh->numtriangles++;
6498 element[1] = element[2];
6502 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6503 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6505 int planenum, planenum2;
6508 mplane_t *plane, *plane2;
6510 double temppoints[2][256*3];
6511 // figure out how large a bounding box we need to properly compute this brush
6513 for (w = 0;w < numplanes;w++)
6514 maxdist = max(maxdist, fabs(planes[w].dist));
6515 // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6516 maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6517 for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6521 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6522 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6524 if (planenum2 == planenum)
6526 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);
6529 if (tempnumpoints < 3)
6531 // generate elements forming a triangle fan for this polygon
6532 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6536 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)
6538 texturelayer_t *layer;
6539 layer = t->currentlayers + t->currentnumlayers++;
6541 layer->depthmask = depthmask;
6542 layer->blendfunc1 = blendfunc1;
6543 layer->blendfunc2 = blendfunc2;
6544 layer->texture = texture;
6545 layer->texmatrix = *matrix;
6546 layer->color[0] = r;
6547 layer->color[1] = g;
6548 layer->color[2] = b;
6549 layer->color[3] = a;
6552 static qboolean R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6554 if(parms[0] == 0 && parms[1] == 0)
6556 if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6557 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6562 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6565 index = parms[2] + rsurface.shadertime * parms[3];
6566 index -= floor(index);
6567 switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6570 case Q3WAVEFUNC_NONE:
6571 case Q3WAVEFUNC_NOISE:
6572 case Q3WAVEFUNC_COUNT:
6575 case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6576 case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6577 case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6578 case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6579 case Q3WAVEFUNC_TRIANGLE:
6581 f = index - floor(index);
6594 f = parms[0] + parms[1] * f;
6595 if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6596 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6600 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6607 matrix4x4_t matrix, temp;
6608 // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6609 // it's better to have one huge fixup every 9 hours than gradual
6610 // degradation over time which looks consistently bad after many hours.
6612 // tcmod scroll in particular suffers from this degradation which can't be
6613 // effectively worked around even with floor() tricks because we don't
6614 // know if tcmod scroll is the last tcmod being applied, and for clampmap
6615 // a workaround involving floor() would be incorrect anyway...
6616 shadertime = rsurface.shadertime;
6617 if (shadertime >= 32768.0f)
6618 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6619 switch(tcmod->tcmod)
6623 if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6624 matrix = r_waterscrollmatrix;
6626 matrix = identitymatrix;
6628 case Q3TCMOD_ENTITYTRANSLATE:
6629 // this is used in Q3 to allow the gamecode to control texcoord
6630 // scrolling on the entity, which is not supported in darkplaces yet.
6631 Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6633 case Q3TCMOD_ROTATE:
6634 Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6635 Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6636 Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6639 Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6641 case Q3TCMOD_SCROLL:
6642 // this particular tcmod is a "bug for bug" compatible one with regards to
6643 // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6644 // specifically did the wrapping and so we must mimic that...
6645 offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6646 offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6647 Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6649 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6650 w = (int) tcmod->parms[0];
6651 h = (int) tcmod->parms[1];
6652 f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6654 idx = (int) floor(f * w * h);
6655 Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6657 case Q3TCMOD_STRETCH:
6658 f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6659 Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6661 case Q3TCMOD_TRANSFORM:
6662 VectorSet(tcmat + 0, tcmod->parms[0], tcmod->parms[1], 0);
6663 VectorSet(tcmat + 3, tcmod->parms[2], tcmod->parms[3], 0);
6664 VectorSet(tcmat + 6, 0 , 0 , 1);
6665 VectorSet(tcmat + 9, tcmod->parms[4], tcmod->parms[5], 0);
6666 Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6668 case Q3TCMOD_TURBULENT:
6669 // this is handled in the RSurf_PrepareVertices function
6670 matrix = identitymatrix;
6674 Matrix4x4_Concat(texmatrix, &matrix, &temp);
6677 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6679 int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6680 char name[MAX_QPATH];
6681 skinframe_t *skinframe;
6682 unsigned char pixels[296*194];
6683 strlcpy(cache->name, skinname, sizeof(cache->name));
6684 dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6685 if (developer_loading.integer)
6686 Con_Printf("loading %s\n", name);
6687 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6688 if (!skinframe || !skinframe->base)
6691 fs_offset_t filesize;
6693 f = FS_LoadFile(name, tempmempool, true, &filesize);
6696 if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6697 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6701 cache->skinframe = skinframe;
6704 texture_t *R_GetCurrentTexture(texture_t *t)
6707 const entity_render_t *ent = rsurface.entity;
6708 dp_model_t *model = ent->model; // when calling this, ent must not be NULL
6709 q3shaderinfo_layer_tcmod_t *tcmod;
6710 float specularscale = 0.0f;
6712 if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6713 return t->currentframe;
6714 t->update_lastrenderframe = r_textureframe;
6715 t->update_lastrenderentity = (void *)ent;
6717 if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6718 t->camera_entity = ent->entitynumber;
6720 t->camera_entity = 0;
6722 // switch to an alternate material if this is a q1bsp animated material
6724 texture_t *texture = t;
6725 int s = rsurface.ent_skinnum;
6726 if ((unsigned int)s >= (unsigned int)model->numskins)
6728 if (model->skinscenes)
6730 if (model->skinscenes[s].framecount > 1)
6731 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6733 s = model->skinscenes[s].firstframe;
6736 t = t + s * model->num_surfaces;
6739 // use an alternate animation if the entity's frame is not 0,
6740 // and only if the texture has an alternate animation
6741 if (t->animated == 2) // q2bsp
6742 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6743 else if (rsurface.ent_alttextures && t->anim_total[1])
6744 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6746 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6748 texture->currentframe = t;
6751 // update currentskinframe to be a qw skin or animation frame
6752 if (rsurface.ent_qwskin >= 0)
6754 i = rsurface.ent_qwskin;
6755 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6757 r_qwskincache_size = cl.maxclients;
6759 Mem_Free(r_qwskincache);
6760 r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6762 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6763 R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6764 t->currentskinframe = r_qwskincache[i].skinframe;
6765 if (t->materialshaderpass && t->currentskinframe == NULL)
6766 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6768 else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6769 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6770 if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6771 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6773 t->currentmaterialflags = t->basematerialflags;
6774 t->currentalpha = rsurface.entity->alpha * t->basealpha;
6775 if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_novis.integer || r_trippy.integer))
6776 t->currentalpha *= r_wateralpha.value;
6777 if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6778 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6779 if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6780 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6782 // decide on which type of lighting to use for this surface
6783 if (rsurface.entity->render_modellight_forced)
6784 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6785 if (rsurface.entity->render_rtlight_disabled)
6786 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6787 if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6789 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6790 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT;
6791 for (q = 0; q < 3; q++)
6793 t->render_glowmod[q] = rsurface.entity->glowmod[q];
6794 t->render_modellight_lightdir[q] = q == 2;
6795 t->render_modellight_ambient[q] = 1;
6796 t->render_modellight_diffuse[q] = 0;
6797 t->render_modellight_specular[q] = 0;
6798 t->render_lightmap_ambient[q] = 0;
6799 t->render_lightmap_diffuse[q] = 0;
6800 t->render_lightmap_specular[q] = 0;
6801 t->render_rtlight_diffuse[q] = 0;
6802 t->render_rtlight_specular[q] = 0;
6805 else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6807 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6808 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT;
6809 for (q = 0; q < 3; q++)
6811 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6812 t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6813 t->render_modellight_lightdir[q] = q == 2;
6814 t->render_modellight_diffuse[q] = 0;
6815 t->render_modellight_specular[q] = 0;
6816 t->render_lightmap_ambient[q] = 0;
6817 t->render_lightmap_diffuse[q] = 0;
6818 t->render_lightmap_specular[q] = 0;
6819 t->render_rtlight_diffuse[q] = 0;
6820 t->render_rtlight_specular[q] = 0;
6823 else if (FAKELIGHT_ENABLED)
6825 // no modellight if using fakelight for the map
6826 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_NORTLIGHT) & ~(MATERIALFLAG_MODELLIGHT);
6827 for (q = 0; q < 3; q++)
6829 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6830 t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6831 t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6832 t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6833 t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6834 t->render_lightmap_ambient[q] = 0;
6835 t->render_lightmap_diffuse[q] = 0;
6836 t->render_lightmap_specular[q] = 0;
6837 t->render_rtlight_diffuse[q] = 0;
6838 t->render_rtlight_specular[q] = 0;
6841 else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6843 // ambient + single direction light (modellight)
6844 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6845 for (q = 0; q < 3; q++)
6847 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6848 t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6849 t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6850 t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6851 t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6852 t->render_lightmap_ambient[q] = 0;
6853 t->render_lightmap_diffuse[q] = 0;
6854 t->render_lightmap_specular[q] = 0;
6855 t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6856 t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6861 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6862 for (q = 0; q < 3; q++)
6864 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6865 t->render_modellight_lightdir[q] = q == 2;
6866 t->render_modellight_ambient[q] = 0;
6867 t->render_modellight_diffuse[q] = 0;
6868 t->render_modellight_specular[q] = 0;
6869 t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6870 t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6871 t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6872 t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6873 t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6877 if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6879 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6880 // attribute, we punt it to the lightmap path and hope for the best,
6881 // but lighting doesn't work.
6883 // FIXME: this is fine for effects but CSQC polygons should be subject
6885 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6886 for (q = 0; q < 3; q++)
6888 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6889 t->render_modellight_lightdir[q] = q == 2;
6890 t->render_modellight_ambient[q] = 0;
6891 t->render_modellight_diffuse[q] = 0;
6892 t->render_modellight_specular[q] = 0;
6893 t->render_lightmap_ambient[q] = 0;
6894 t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6895 t->render_lightmap_specular[q] = 0;
6896 t->render_rtlight_diffuse[q] = 0;
6897 t->render_rtlight_specular[q] = 0;
6901 for (q = 0; q < 3; q++)
6903 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6904 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6907 if (rsurface.ent_flags & RENDER_ADDITIVE)
6908 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6909 else if (t->currentalpha < 1)
6910 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6911 // LordHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6912 if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6913 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6914 if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6915 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6916 if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6917 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6918 if (t->backgroundshaderpass)
6919 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6920 if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6922 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6923 t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6926 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6927 if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6929 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6930 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6932 if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6933 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6935 // there is no tcmod
6936 if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6938 t->currenttexmatrix = r_waterscrollmatrix;
6939 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6941 else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6943 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6944 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6947 if (t->materialshaderpass)
6948 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6949 R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6951 t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6952 if (t->currentskinframe->qpixels)
6953 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6954 t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6955 if (!t->basetexture)
6956 t->basetexture = r_texture_notexture;
6957 t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6958 t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6959 t->nmaptexture = t->currentskinframe->nmap;
6960 if (!t->nmaptexture)
6961 t->nmaptexture = r_texture_blanknormalmap;
6962 t->glosstexture = r_texture_black;
6963 t->glowtexture = t->currentskinframe->glow;
6964 t->fogtexture = t->currentskinframe->fog;
6965 t->reflectmasktexture = t->currentskinframe->reflect;
6966 if (t->backgroundshaderpass)
6968 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6969 R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6970 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6971 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6972 t->backgroundglosstexture = r_texture_black;
6973 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6974 if (!t->backgroundnmaptexture)
6975 t->backgroundnmaptexture = r_texture_blanknormalmap;
6976 // make sure that if glow is going to be used, both textures are not NULL
6977 if (!t->backgroundglowtexture && t->glowtexture)
6978 t->backgroundglowtexture = r_texture_black;
6979 if (!t->glowtexture && t->backgroundglowtexture)
6980 t->glowtexture = r_texture_black;
6984 t->backgroundbasetexture = r_texture_white;
6985 t->backgroundnmaptexture = r_texture_blanknormalmap;
6986 t->backgroundglosstexture = r_texture_black;
6987 t->backgroundglowtexture = NULL;
6989 t->specularpower = r_shadow_glossexponent.value;
6990 // TODO: store reference values for these in the texture?
6991 if (r_shadow_gloss.integer > 0)
6993 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
6995 if (r_shadow_glossintensity.value > 0)
6997 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
6998 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
6999 specularscale = r_shadow_glossintensity.value;
7002 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
7004 t->glosstexture = r_texture_white;
7005 t->backgroundglosstexture = r_texture_white;
7006 specularscale = r_shadow_gloss2intensity.value;
7007 t->specularpower = r_shadow_gloss2exponent.value;
7010 specularscale *= t->specularscalemod;
7011 t->specularpower *= t->specularpowermod;
7013 // lightmaps mode looks bad with dlights using actual texturing, so turn
7014 // off the colormap and glossmap, but leave the normalmap on as it still
7015 // accurately represents the shading involved
7016 if (gl_lightmaps.integer)
7018 t->basetexture = r_texture_grey128;
7019 t->pantstexture = r_texture_black;
7020 t->shirttexture = r_texture_black;
7021 if (gl_lightmaps.integer < 2)
7022 t->nmaptexture = r_texture_blanknormalmap;
7023 t->glosstexture = r_texture_black;
7024 t->glowtexture = NULL;
7025 t->fogtexture = NULL;
7026 t->reflectmasktexture = NULL;
7027 t->backgroundbasetexture = NULL;
7028 if (gl_lightmaps.integer < 2)
7029 t->backgroundnmaptexture = r_texture_blanknormalmap;
7030 t->backgroundglosstexture = r_texture_black;
7031 t->backgroundglowtexture = NULL;
7033 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
7036 if (specularscale != 1.0f)
7038 for (q = 0; q < 3; q++)
7040 t->render_modellight_specular[q] *= specularscale;
7041 t->render_lightmap_specular[q] *= specularscale;
7042 t->render_rtlight_specular[q] *= specularscale;
7046 t->currentnumlayers = 0;
7047 if (t->currentmaterialflags & MATERIALFLAG_WALL)
7049 int blendfunc1, blendfunc2;
7051 if (t->currentmaterialflags & MATERIALFLAG_ADD)
7053 blendfunc1 = GL_SRC_ALPHA;
7054 blendfunc2 = GL_ONE;
7056 else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
7058 blendfunc1 = GL_SRC_ALPHA;
7059 blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
7061 else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
7063 blendfunc1 = t->customblendfunc[0];
7064 blendfunc2 = t->customblendfunc[1];
7068 blendfunc1 = GL_ONE;
7069 blendfunc2 = GL_ZERO;
7071 depthmask = !(t->currentmaterialflags & MATERIALFLAG_BLENDED);
7072 if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
7074 // basic lit geometry
7075 R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE, t->basetexture, &t->currenttexmatrix, 2, 2, 2, t->currentalpha);
7076 // add pants/shirt if needed
7077 if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7078 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);
7079 if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7080 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);
7084 // basic lit geometry
7085 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);
7086 // add pants/shirt if needed
7087 if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7088 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->pantstexture, &t->currenttexmatrix, 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);
7089 if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7090 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->shirttexture, &t->currenttexmatrix, 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);
7091 // now add ambient passes if needed
7092 if (VectorLength2(t->render_lightmap_ambient) >= (1.0f/1048576.0f))
7094 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);
7095 if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7096 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);
7097 if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7098 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);
7101 if (t->glowtexture != NULL && !gl_lightmaps.integer)
7102 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);
7103 if (r_refdef.fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD))
7105 // if this is opaque use alpha blend which will darken the earlier
7108 // if this is an alpha blended material, all the earlier passes
7109 // were darkened by fog already, so we only need to add the fog
7110 // color ontop through the fog mask texture
7112 // if this is an additive blended material, all the earlier passes
7113 // were darkened by fog already, and we should not add fog color
7114 // (because the background was not darkened, there is no fog color
7115 // that was lost behind it).
7116 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);
7123 rsurfacestate_t rsurface;
7125 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
7127 dp_model_t *model = ent->model;
7128 //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
7130 rsurface.entity = (entity_render_t *)ent;
7131 rsurface.skeleton = ent->skeleton;
7132 memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
7133 rsurface.ent_skinnum = ent->skinnum;
7134 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;
7135 rsurface.ent_flags = ent->flags;
7136 if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
7137 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
7138 rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
7139 rsurface.matrix = ent->matrix;
7140 rsurface.inversematrix = ent->inversematrix;
7141 rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7142 rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7143 R_EntityMatrix(&rsurface.matrix);
7144 Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7145 Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7146 rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
7147 rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7148 rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7149 rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7150 memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
7151 rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
7152 rsurface.basepolygonfactor = r_refdef.polygonfactor;
7153 rsurface.basepolygonoffset = r_refdef.polygonoffset;
7154 if (ent->model->brush.submodel && !prepass)
7156 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
7157 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
7159 // if the animcache code decided it should use the shader path, skip the deform step
7160 rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
7161 rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
7162 rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
7163 rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
7164 rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
7165 if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
7167 if (ent->animcache_vertex3f)
7169 r_refdef.stats[r_stat_batch_entitycache_count]++;
7170 r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
7171 r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
7172 r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
7173 rsurface.modelvertex3f = ent->animcache_vertex3f;
7174 rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
7175 rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
7176 rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
7177 rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
7178 rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
7179 rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
7180 rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
7181 rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
7182 rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
7183 rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
7184 rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
7185 rsurface.modelvertexmesh = ent->animcache_vertexmesh;
7186 rsurface.modelvertexmesh_vertexbuffer = ent->animcache_vertexmesh_vertexbuffer;
7187 rsurface.modelvertexmesh_bufferoffset = ent->animcache_vertexmesh_bufferoffset;
7189 else if (wanttangents)
7191 r_refdef.stats[r_stat_batch_entityanimate_count]++;
7192 r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7193 r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7194 r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7195 rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7196 rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7197 rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7198 rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7199 model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
7200 rsurface.modelvertexmesh = NULL;
7201 rsurface.modelvertexmesh_vertexbuffer = NULL;
7202 rsurface.modelvertexmesh_bufferoffset = 0;
7203 rsurface.modelvertex3f_vertexbuffer = NULL;
7204 rsurface.modelvertex3f_bufferoffset = 0;
7205 rsurface.modelvertex3f_vertexbuffer = 0;
7206 rsurface.modelvertex3f_bufferoffset = 0;
7207 rsurface.modelsvector3f_vertexbuffer = 0;
7208 rsurface.modelsvector3f_bufferoffset = 0;
7209 rsurface.modeltvector3f_vertexbuffer = 0;
7210 rsurface.modeltvector3f_bufferoffset = 0;
7211 rsurface.modelnormal3f_vertexbuffer = 0;
7212 rsurface.modelnormal3f_bufferoffset = 0;
7214 else if (wantnormals)
7216 r_refdef.stats[r_stat_batch_entityanimate_count]++;
7217 r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7218 r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7219 r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7220 rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7221 rsurface.modelsvector3f = NULL;
7222 rsurface.modeltvector3f = NULL;
7223 rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7224 model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
7225 rsurface.modelvertexmesh = NULL;
7226 rsurface.modelvertexmesh_vertexbuffer = NULL;
7227 rsurface.modelvertexmesh_bufferoffset = 0;
7228 rsurface.modelvertex3f_vertexbuffer = NULL;
7229 rsurface.modelvertex3f_bufferoffset = 0;
7230 rsurface.modelvertex3f_vertexbuffer = 0;
7231 rsurface.modelvertex3f_bufferoffset = 0;
7232 rsurface.modelsvector3f_vertexbuffer = 0;
7233 rsurface.modelsvector3f_bufferoffset = 0;
7234 rsurface.modeltvector3f_vertexbuffer = 0;
7235 rsurface.modeltvector3f_bufferoffset = 0;
7236 rsurface.modelnormal3f_vertexbuffer = 0;
7237 rsurface.modelnormal3f_bufferoffset = 0;
7241 r_refdef.stats[r_stat_batch_entityanimate_count]++;
7242 r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7243 r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7244 r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7245 rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7246 rsurface.modelsvector3f = NULL;
7247 rsurface.modeltvector3f = NULL;
7248 rsurface.modelnormal3f = NULL;
7249 model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7250 rsurface.modelvertexmesh = NULL;
7251 rsurface.modelvertexmesh_vertexbuffer = NULL;
7252 rsurface.modelvertexmesh_bufferoffset = 0;
7253 rsurface.modelvertex3f_vertexbuffer = NULL;
7254 rsurface.modelvertex3f_bufferoffset = 0;
7255 rsurface.modelvertex3f_vertexbuffer = 0;
7256 rsurface.modelvertex3f_bufferoffset = 0;
7257 rsurface.modelsvector3f_vertexbuffer = 0;
7258 rsurface.modelsvector3f_bufferoffset = 0;
7259 rsurface.modeltvector3f_vertexbuffer = 0;
7260 rsurface.modeltvector3f_bufferoffset = 0;
7261 rsurface.modelnormal3f_vertexbuffer = 0;
7262 rsurface.modelnormal3f_bufferoffset = 0;
7264 rsurface.modelgeneratedvertex = true;
7268 if (rsurface.entityskeletaltransform3x4)
7270 r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7271 r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7272 r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7273 r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7277 r_refdef.stats[r_stat_batch_entitystatic_count]++;
7278 r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7279 r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7280 r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7282 rsurface.modelvertex3f = model->surfmesh.data_vertex3f;
7283 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7284 rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
7285 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7286 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7287 rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f;
7288 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7289 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7290 rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f;
7291 rsurface.modelnormal3f = model->surfmesh.data_normal3f;
7292 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7293 rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f;
7294 rsurface.modelvertexmesh = model->surfmesh.data_vertexmesh;
7295 rsurface.modelvertexmesh_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7296 rsurface.modelvertexmesh_bufferoffset = model->surfmesh.vbooffset_vertex3f;
7297 rsurface.modelgeneratedvertex = false;
7299 rsurface.modellightmapcolor4f = model->surfmesh.data_lightmapcolor4f;
7300 rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7301 rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f;
7302 rsurface.modeltexcoordtexture2f = model->surfmesh.data_texcoordtexture2f;
7303 rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7304 rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f;
7305 rsurface.modeltexcoordlightmap2f = model->surfmesh.data_texcoordlightmap2f;
7306 rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7307 rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
7308 rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7309 rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7310 rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.vbooffset_skeletalindex4ub;
7311 rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7312 rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7313 rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.vbooffset_skeletalweight4ub;
7314 rsurface.modelelement3i = model->surfmesh.data_element3i;
7315 rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7316 rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7317 rsurface.modelelement3s = model->surfmesh.data_element3s;
7318 rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7319 rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7320 rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7321 rsurface.modelnumvertices = model->surfmesh.num_vertices;
7322 rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7323 rsurface.modelsurfaces = model->data_surfaces;
7324 rsurface.batchgeneratedvertex = false;
7325 rsurface.batchfirstvertex = 0;
7326 rsurface.batchnumvertices = 0;
7327 rsurface.batchfirsttriangle = 0;
7328 rsurface.batchnumtriangles = 0;
7329 rsurface.batchvertex3f = NULL;
7330 rsurface.batchvertex3f_vertexbuffer = NULL;
7331 rsurface.batchvertex3f_bufferoffset = 0;
7332 rsurface.batchsvector3f = NULL;
7333 rsurface.batchsvector3f_vertexbuffer = NULL;
7334 rsurface.batchsvector3f_bufferoffset = 0;
7335 rsurface.batchtvector3f = NULL;
7336 rsurface.batchtvector3f_vertexbuffer = NULL;
7337 rsurface.batchtvector3f_bufferoffset = 0;
7338 rsurface.batchnormal3f = NULL;
7339 rsurface.batchnormal3f_vertexbuffer = NULL;
7340 rsurface.batchnormal3f_bufferoffset = 0;
7341 rsurface.batchlightmapcolor4f = NULL;
7342 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7343 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7344 rsurface.batchtexcoordtexture2f = NULL;
7345 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7346 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7347 rsurface.batchtexcoordlightmap2f = NULL;
7348 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7349 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7350 rsurface.batchskeletalindex4ub = NULL;
7351 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7352 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7353 rsurface.batchskeletalweight4ub = NULL;
7354 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7355 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7356 rsurface.batchvertexmesh = NULL;
7357 rsurface.batchvertexmesh_vertexbuffer = NULL;
7358 rsurface.batchvertexmesh_bufferoffset = 0;
7359 rsurface.batchelement3i = NULL;
7360 rsurface.batchelement3i_indexbuffer = NULL;
7361 rsurface.batchelement3i_bufferoffset = 0;
7362 rsurface.batchelement3s = NULL;
7363 rsurface.batchelement3s_indexbuffer = NULL;
7364 rsurface.batchelement3s_bufferoffset = 0;
7365 rsurface.forcecurrenttextureupdate = false;
7368 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)
7370 rsurface.entity = r_refdef.scene.worldentity;
7371 rsurface.skeleton = NULL;
7372 rsurface.ent_skinnum = 0;
7373 rsurface.ent_qwskin = -1;
7374 rsurface.ent_flags = entflags;
7375 rsurface.shadertime = r_refdef.scene.time - shadertime;
7376 rsurface.modelnumvertices = numvertices;
7377 rsurface.modelnumtriangles = numtriangles;
7378 rsurface.matrix = *matrix;
7379 rsurface.inversematrix = *inversematrix;
7380 rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7381 rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7382 R_EntityMatrix(&rsurface.matrix);
7383 Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7384 Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7385 rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7386 rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7387 rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7388 rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7389 memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7390 rsurface.frameblend[0].lerp = 1;
7391 rsurface.ent_alttextures = false;
7392 rsurface.basepolygonfactor = r_refdef.polygonfactor;
7393 rsurface.basepolygonoffset = r_refdef.polygonoffset;
7394 rsurface.entityskeletaltransform3x4 = NULL;
7395 rsurface.entityskeletaltransform3x4buffer = NULL;
7396 rsurface.entityskeletaltransform3x4offset = 0;
7397 rsurface.entityskeletaltransform3x4size = 0;
7398 rsurface.entityskeletalnumtransforms = 0;
7399 r_refdef.stats[r_stat_batch_entitycustom_count]++;
7400 r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7401 r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7402 r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7405 rsurface.modelvertex3f = (float *)vertex3f;
7406 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7407 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7408 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7410 else if (wantnormals)
7412 rsurface.modelvertex3f = (float *)vertex3f;
7413 rsurface.modelsvector3f = NULL;
7414 rsurface.modeltvector3f = NULL;
7415 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7419 rsurface.modelvertex3f = (float *)vertex3f;
7420 rsurface.modelsvector3f = NULL;
7421 rsurface.modeltvector3f = NULL;
7422 rsurface.modelnormal3f = NULL;
7424 rsurface.modelvertexmesh = NULL;
7425 rsurface.modelvertexmesh_vertexbuffer = NULL;
7426 rsurface.modelvertexmesh_bufferoffset = 0;
7427 rsurface.modelvertex3f_vertexbuffer = 0;
7428 rsurface.modelvertex3f_bufferoffset = 0;
7429 rsurface.modelsvector3f_vertexbuffer = 0;
7430 rsurface.modelsvector3f_bufferoffset = 0;
7431 rsurface.modeltvector3f_vertexbuffer = 0;
7432 rsurface.modeltvector3f_bufferoffset = 0;
7433 rsurface.modelnormal3f_vertexbuffer = 0;
7434 rsurface.modelnormal3f_bufferoffset = 0;
7435 rsurface.modelgeneratedvertex = true;
7436 rsurface.modellightmapcolor4f = (float *)color4f;
7437 rsurface.modellightmapcolor4f_vertexbuffer = 0;
7438 rsurface.modellightmapcolor4f_bufferoffset = 0;
7439 rsurface.modeltexcoordtexture2f = (float *)texcoord2f;
7440 rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7441 rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7442 rsurface.modeltexcoordlightmap2f = NULL;
7443 rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7444 rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7445 rsurface.modelskeletalindex4ub = NULL;
7446 rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7447 rsurface.modelskeletalindex4ub_bufferoffset = 0;
7448 rsurface.modelskeletalweight4ub = NULL;
7449 rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7450 rsurface.modelskeletalweight4ub_bufferoffset = 0;
7451 rsurface.modelelement3i = (int *)element3i;
7452 rsurface.modelelement3i_indexbuffer = NULL;
7453 rsurface.modelelement3i_bufferoffset = 0;
7454 rsurface.modelelement3s = (unsigned short *)element3s;
7455 rsurface.modelelement3s_indexbuffer = NULL;
7456 rsurface.modelelement3s_bufferoffset = 0;
7457 rsurface.modellightmapoffsets = NULL;
7458 rsurface.modelsurfaces = NULL;
7459 rsurface.batchgeneratedvertex = false;
7460 rsurface.batchfirstvertex = 0;
7461 rsurface.batchnumvertices = 0;
7462 rsurface.batchfirsttriangle = 0;
7463 rsurface.batchnumtriangles = 0;
7464 rsurface.batchvertex3f = NULL;
7465 rsurface.batchvertex3f_vertexbuffer = NULL;
7466 rsurface.batchvertex3f_bufferoffset = 0;
7467 rsurface.batchsvector3f = NULL;
7468 rsurface.batchsvector3f_vertexbuffer = NULL;
7469 rsurface.batchsvector3f_bufferoffset = 0;
7470 rsurface.batchtvector3f = NULL;
7471 rsurface.batchtvector3f_vertexbuffer = NULL;
7472 rsurface.batchtvector3f_bufferoffset = 0;
7473 rsurface.batchnormal3f = NULL;
7474 rsurface.batchnormal3f_vertexbuffer = NULL;
7475 rsurface.batchnormal3f_bufferoffset = 0;
7476 rsurface.batchlightmapcolor4f = NULL;
7477 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7478 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7479 rsurface.batchtexcoordtexture2f = NULL;
7480 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7481 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7482 rsurface.batchtexcoordlightmap2f = NULL;
7483 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7484 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7485 rsurface.batchskeletalindex4ub = NULL;
7486 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7487 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7488 rsurface.batchskeletalweight4ub = NULL;
7489 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7490 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7491 rsurface.batchvertexmesh = NULL;
7492 rsurface.batchvertexmesh_vertexbuffer = NULL;
7493 rsurface.batchvertexmesh_bufferoffset = 0;
7494 rsurface.batchelement3i = NULL;
7495 rsurface.batchelement3i_indexbuffer = NULL;
7496 rsurface.batchelement3i_bufferoffset = 0;
7497 rsurface.batchelement3s = NULL;
7498 rsurface.batchelement3s_indexbuffer = NULL;
7499 rsurface.batchelement3s_bufferoffset = 0;
7500 rsurface.forcecurrenttextureupdate = true;
7502 if (rsurface.modelnumvertices && rsurface.modelelement3i)
7504 if ((wantnormals || wanttangents) && !normal3f)
7506 rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7507 Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7509 if (wanttangents && !svector3f)
7511 rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7512 rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7513 Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7518 float RSurf_FogPoint(const float *v)
7520 // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7521 float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7522 float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7523 float FogHeightFade = r_refdef.fogheightfade;
7525 unsigned int fogmasktableindex;
7526 if (r_refdef.fogplaneviewabove)
7527 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7529 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7530 fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7531 return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7534 float RSurf_FogVertex(const float *v)
7536 // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7537 float FogPlaneViewDist = rsurface.fogplaneviewdist;
7538 float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7539 float FogHeightFade = rsurface.fogheightfade;
7541 unsigned int fogmasktableindex;
7542 if (r_refdef.fogplaneviewabove)
7543 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7545 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7546 fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7547 return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7550 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7553 for (i = 0;i < numelements;i++)
7554 outelement3i[i] = inelement3i[i] + adjust;
7557 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7558 extern cvar_t gl_vbo;
7559 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7567 int surfacefirsttriangle;
7568 int surfacenumtriangles;
7569 int surfacefirstvertex;
7570 int surfaceendvertex;
7571 int surfacenumvertices;
7572 int batchnumsurfaces = texturenumsurfaces;
7573 int batchnumvertices;
7574 int batchnumtriangles;
7578 qboolean dynamicvertex;
7581 float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7584 q3shaderinfo_deform_t *deform;
7585 const msurface_t *surface, *firstsurface;
7586 r_vertexmesh_t *vertexmesh;
7587 if (!texturenumsurfaces)
7589 // find vertex range of this surface batch
7591 firstsurface = texturesurfacelist[0];
7592 firsttriangle = firstsurface->num_firsttriangle;
7593 batchnumvertices = 0;
7594 batchnumtriangles = 0;
7595 firstvertex = endvertex = firstsurface->num_firstvertex;
7596 for (i = 0;i < texturenumsurfaces;i++)
7598 surface = texturesurfacelist[i];
7599 if (surface != firstsurface + i)
7601 surfacefirstvertex = surface->num_firstvertex;
7602 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7603 surfacenumvertices = surface->num_vertices;
7604 surfacenumtriangles = surface->num_triangles;
7605 if (firstvertex > surfacefirstvertex)
7606 firstvertex = surfacefirstvertex;
7607 if (endvertex < surfaceendvertex)
7608 endvertex = surfaceendvertex;
7609 batchnumvertices += surfacenumvertices;
7610 batchnumtriangles += surfacenumtriangles;
7613 r_refdef.stats[r_stat_batch_batches]++;
7615 r_refdef.stats[r_stat_batch_withgaps]++;
7616 r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7617 r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7618 r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7620 // we now know the vertex range used, and if there are any gaps in it
7621 rsurface.batchfirstvertex = firstvertex;
7622 rsurface.batchnumvertices = endvertex - firstvertex;
7623 rsurface.batchfirsttriangle = firsttriangle;
7624 rsurface.batchnumtriangles = batchnumtriangles;
7626 // this variable holds flags for which properties have been updated that
7627 // may require regenerating vertexmesh array...
7630 // check if any dynamic vertex processing must occur
7631 dynamicvertex = false;
7633 // a cvar to force the dynamic vertex path to be taken, for debugging
7634 if (r_batch_debugdynamicvertexpath.integer)
7638 r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7639 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7640 r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7641 r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7643 dynamicvertex = true;
7646 // if there is a chance of animated vertex colors, it's a dynamic batch
7647 if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo)
7651 r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7652 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7653 r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7654 r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7656 dynamicvertex = true;
7657 needsupdate |= BATCHNEED_VERTEXMESH_VERTEXCOLOR;
7660 for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7662 switch (deform->deform)
7665 case Q3DEFORM_PROJECTIONSHADOW:
7666 case Q3DEFORM_TEXT0:
7667 case Q3DEFORM_TEXT1:
7668 case Q3DEFORM_TEXT2:
7669 case Q3DEFORM_TEXT3:
7670 case Q3DEFORM_TEXT4:
7671 case Q3DEFORM_TEXT5:
7672 case Q3DEFORM_TEXT6:
7673 case Q3DEFORM_TEXT7:
7676 case Q3DEFORM_AUTOSPRITE:
7679 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7680 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7681 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7682 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7684 dynamicvertex = true;
7685 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7686 needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7688 case Q3DEFORM_AUTOSPRITE2:
7691 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7692 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7693 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7694 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7696 dynamicvertex = true;
7697 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7698 needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7700 case Q3DEFORM_NORMAL:
7703 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7704 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7705 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7706 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7708 dynamicvertex = true;
7709 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7710 needsupdate |= BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7713 if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7714 break; // if wavefunc is a nop, ignore this transform
7717 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7718 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7719 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7720 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7722 dynamicvertex = true;
7723 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7724 needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7726 case Q3DEFORM_BULGE:
7729 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7730 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7731 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7732 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7734 dynamicvertex = true;
7735 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7736 needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7739 if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7740 break; // if wavefunc is a nop, ignore this transform
7743 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7744 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7745 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7746 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7748 dynamicvertex = true;
7749 batchneed |= BATCHNEED_ARRAY_VERTEX;
7750 needsupdate |= BATCHNEED_VERTEXMESH_VERTEX;
7754 if (rsurface.texture->materialshaderpass)
7756 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7759 case Q3TCGEN_TEXTURE:
7761 case Q3TCGEN_LIGHTMAP:
7764 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7765 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7766 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7767 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7769 dynamicvertex = true;
7770 batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7771 needsupdate |= BATCHNEED_VERTEXMESH_LIGHTMAP;
7773 case Q3TCGEN_VECTOR:
7776 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7777 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7778 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7779 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7781 dynamicvertex = true;
7782 batchneed |= BATCHNEED_ARRAY_VERTEX;
7783 needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
7785 case Q3TCGEN_ENVIRONMENT:
7788 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7789 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7790 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7791 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7793 dynamicvertex = true;
7794 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7795 needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
7798 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7802 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7803 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7804 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7805 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7807 dynamicvertex = true;
7808 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7809 needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
7813 if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)))
7817 r_refdef.stats[r_stat_batch_dynamic_batches_because_interleavedarrays] += 1;
7818 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_interleavedarrays] += batchnumsurfaces;
7819 r_refdef.stats[r_stat_batch_dynamic_vertices_because_interleavedarrays] += batchnumvertices;
7820 r_refdef.stats[r_stat_batch_dynamic_triangles_because_interleavedarrays] += batchnumtriangles;
7822 dynamicvertex = true;
7823 needsupdate |= (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP));
7826 // when the model data has no vertex buffer (dynamic mesh), we need to
7828 if (vid.useinterleavedarrays && !rsurface.modelvertexmesh_vertexbuffer)
7829 batchneed |= BATCHNEED_NOGAPS;
7831 // the caller can specify BATCHNEED_NOGAPS to force a batch with
7832 // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7833 // we ensure this by treating the vertex batch as dynamic...
7834 if ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0))
7838 r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7839 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7840 r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7841 r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7843 dynamicvertex = true;
7848 // when copying, we need to consider the regeneration of vertexmesh, any dependencies it may have must be set...
7849 if (batchneed & BATCHNEED_VERTEXMESH_VERTEX) batchneed |= BATCHNEED_ARRAY_VERTEX;
7850 if (batchneed & BATCHNEED_VERTEXMESH_NORMAL) batchneed |= BATCHNEED_ARRAY_NORMAL;
7851 if (batchneed & BATCHNEED_VERTEXMESH_VECTOR) batchneed |= BATCHNEED_ARRAY_VECTOR;
7852 if (batchneed & BATCHNEED_VERTEXMESH_VERTEXCOLOR) batchneed |= BATCHNEED_ARRAY_VERTEXCOLOR;
7853 if (batchneed & BATCHNEED_VERTEXMESH_TEXCOORD) batchneed |= BATCHNEED_ARRAY_TEXCOORD;
7854 if (batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP) batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7855 if (batchneed & BATCHNEED_VERTEXMESH_SKELETAL) batchneed |= BATCHNEED_ARRAY_SKELETAL;
7858 // if needsupdate, we have to do a dynamic vertex batch for sure
7859 if (needsupdate & batchneed)
7863 r_refdef.stats[r_stat_batch_dynamic_batches_because_derived] += 1;
7864 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_derived] += batchnumsurfaces;
7865 r_refdef.stats[r_stat_batch_dynamic_vertices_because_derived] += batchnumvertices;
7866 r_refdef.stats[r_stat_batch_dynamic_triangles_because_derived] += batchnumtriangles;
7868 dynamicvertex = true;
7871 // see if we need to build vertexmesh from arrays
7872 if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)))
7876 r_refdef.stats[r_stat_batch_dynamic_batches_because_interleavedarrays] += 1;
7877 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_interleavedarrays] += batchnumsurfaces;
7878 r_refdef.stats[r_stat_batch_dynamic_vertices_because_interleavedarrays] += batchnumvertices;
7879 r_refdef.stats[r_stat_batch_dynamic_triangles_because_interleavedarrays] += batchnumtriangles;
7881 dynamicvertex = true;
7884 // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7885 if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7886 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7888 rsurface.batchvertex3f = rsurface.modelvertex3f;
7889 rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7890 rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7891 rsurface.batchsvector3f = rsurface.modelsvector3f;
7892 rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7893 rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7894 rsurface.batchtvector3f = rsurface.modeltvector3f;
7895 rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7896 rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7897 rsurface.batchnormal3f = rsurface.modelnormal3f;
7898 rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7899 rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7900 rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7901 rsurface.batchlightmapcolor4f_vertexbuffer = rsurface.modellightmapcolor4f_vertexbuffer;
7902 rsurface.batchlightmapcolor4f_bufferoffset = rsurface.modellightmapcolor4f_bufferoffset;
7903 rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7904 rsurface.batchtexcoordtexture2f_vertexbuffer = rsurface.modeltexcoordtexture2f_vertexbuffer;
7905 rsurface.batchtexcoordtexture2f_bufferoffset = rsurface.modeltexcoordtexture2f_bufferoffset;
7906 rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7907 rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7908 rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7909 rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7910 rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7911 rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7912 rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7913 rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7914 rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7915 rsurface.batchvertexmesh = rsurface.modelvertexmesh;
7916 rsurface.batchvertexmesh_vertexbuffer = rsurface.modelvertexmesh_vertexbuffer;
7917 rsurface.batchvertexmesh_bufferoffset = rsurface.modelvertexmesh_bufferoffset;
7918 rsurface.batchelement3i = rsurface.modelelement3i;
7919 rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7920 rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7921 rsurface.batchelement3s = rsurface.modelelement3s;
7922 rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7923 rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7924 rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7925 rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7926 rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7927 rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7928 rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7930 // if any dynamic vertex processing has to occur in software, we copy the
7931 // entire surface list together before processing to rebase the vertices
7932 // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7934 // if any gaps exist and we do not have a static vertex buffer, we have to
7935 // copy the surface list together to avoid wasting upload bandwidth on the
7936 // vertices in the gaps.
7938 // if gaps exist and we have a static vertex buffer, we can choose whether
7939 // to combine the index buffer ranges into one dynamic index buffer or
7940 // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7942 // in many cases the batch is reduced to one draw call.
7944 rsurface.batchmultidraw = false;
7945 rsurface.batchmultidrawnumsurfaces = 0;
7946 rsurface.batchmultidrawsurfacelist = NULL;
7950 // static vertex data, just set pointers...
7951 rsurface.batchgeneratedvertex = false;
7952 // if there are gaps, we want to build a combined index buffer,
7953 // otherwise use the original static buffer with an appropriate offset
7956 r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7957 r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7958 r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7959 r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7960 if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7962 rsurface.batchmultidraw = true;
7963 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7964 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7967 // build a new triangle elements array for this batch
7968 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7969 rsurface.batchfirsttriangle = 0;
7971 for (i = 0;i < texturenumsurfaces;i++)
7973 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7974 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7975 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7976 numtriangles += surfacenumtriangles;
7978 rsurface.batchelement3i_indexbuffer = NULL;
7979 rsurface.batchelement3i_bufferoffset = 0;
7980 rsurface.batchelement3s = NULL;
7981 rsurface.batchelement3s_indexbuffer = NULL;
7982 rsurface.batchelement3s_bufferoffset = 0;
7983 if (endvertex <= 65536)
7985 // make a 16bit (unsigned short) index array if possible
7986 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7987 for (i = 0;i < numtriangles*3;i++)
7988 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7990 // upload buffer data for the copytriangles batch
7991 if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo)
7993 if (rsurface.batchelement3s)
7994 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
7995 else if (rsurface.batchelement3i)
7996 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
8001 r_refdef.stats[r_stat_batch_fast_batches] += 1;
8002 r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
8003 r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
8004 r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
8009 // something needs software processing, do it for real...
8010 // we only directly handle separate array data in this case and then
8011 // generate interleaved data if needed...
8012 rsurface.batchgeneratedvertex = true;
8013 r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
8014 r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
8015 r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
8016 r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
8018 // now copy the vertex data into a combined array and make an index array
8019 // (this is what Quake3 does all the time)
8020 // we also apply any skeletal animation here that would have been done in
8021 // the vertex shader, because most of the dynamic vertex animation cases
8022 // need actual vertex positions and normals
8023 //if (dynamicvertex)
8025 rsurface.batchvertexmesh = NULL;
8026 rsurface.batchvertexmesh_vertexbuffer = NULL;
8027 rsurface.batchvertexmesh_bufferoffset = 0;
8028 rsurface.batchvertex3f = NULL;
8029 rsurface.batchvertex3f_vertexbuffer = NULL;
8030 rsurface.batchvertex3f_bufferoffset = 0;
8031 rsurface.batchsvector3f = NULL;
8032 rsurface.batchsvector3f_vertexbuffer = NULL;
8033 rsurface.batchsvector3f_bufferoffset = 0;
8034 rsurface.batchtvector3f = NULL;
8035 rsurface.batchtvector3f_vertexbuffer = NULL;
8036 rsurface.batchtvector3f_bufferoffset = 0;
8037 rsurface.batchnormal3f = NULL;
8038 rsurface.batchnormal3f_vertexbuffer = NULL;
8039 rsurface.batchnormal3f_bufferoffset = 0;
8040 rsurface.batchlightmapcolor4f = NULL;
8041 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8042 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8043 rsurface.batchtexcoordtexture2f = NULL;
8044 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8045 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8046 rsurface.batchtexcoordlightmap2f = NULL;
8047 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
8048 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
8049 rsurface.batchskeletalindex4ub = NULL;
8050 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
8051 rsurface.batchskeletalindex4ub_bufferoffset = 0;
8052 rsurface.batchskeletalweight4ub = NULL;
8053 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
8054 rsurface.batchskeletalweight4ub_bufferoffset = 0;
8055 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
8056 rsurface.batchelement3i_indexbuffer = NULL;
8057 rsurface.batchelement3i_bufferoffset = 0;
8058 rsurface.batchelement3s = NULL;
8059 rsurface.batchelement3s_indexbuffer = NULL;
8060 rsurface.batchelement3s_bufferoffset = 0;
8061 rsurface.batchskeletaltransform3x4buffer = NULL;
8062 rsurface.batchskeletaltransform3x4offset = 0;
8063 rsurface.batchskeletaltransform3x4size = 0;
8064 // we'll only be setting up certain arrays as needed
8065 if (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP))
8066 rsurface.batchvertexmesh = (r_vertexmesh_t *)R_FrameData_Alloc(batchnumvertices * sizeof(r_vertexmesh_t));
8067 if (batchneed & BATCHNEED_ARRAY_VERTEX)
8068 rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8069 if (batchneed & BATCHNEED_ARRAY_NORMAL)
8070 rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8071 if (batchneed & BATCHNEED_ARRAY_VECTOR)
8073 rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8074 rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8076 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
8077 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8078 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
8079 rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8080 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
8081 rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8082 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
8084 rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
8085 rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
8089 for (i = 0;i < texturenumsurfaces;i++)
8091 surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
8092 surfacenumvertices = texturesurfacelist[i]->num_vertices;
8093 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
8094 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
8095 // copy only the data requested
8096 if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)) && rsurface.modelvertexmesh)
8097 memcpy(rsurface.batchvertexmesh + numvertices, rsurface.modelvertexmesh + surfacefirstvertex, surfacenumvertices * sizeof(rsurface.batchvertexmesh[0]));
8098 if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
8100 if (batchneed & BATCHNEED_ARRAY_VERTEX)
8102 if (rsurface.batchvertex3f)
8103 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8105 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8107 if (batchneed & BATCHNEED_ARRAY_NORMAL)
8109 if (rsurface.modelnormal3f)
8110 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8112 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8114 if (batchneed & BATCHNEED_ARRAY_VECTOR)
8116 if (rsurface.modelsvector3f)
8118 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8119 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8123 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8124 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8127 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
8129 if (rsurface.modellightmapcolor4f)
8130 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
8132 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
8134 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
8136 if (rsurface.modeltexcoordtexture2f)
8137 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
8139 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
8141 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
8143 if (rsurface.modeltexcoordlightmap2f)
8144 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
8146 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
8148 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
8150 if (rsurface.modelskeletalindex4ub)
8152 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
8153 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
8157 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
8158 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
8159 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
8160 for (j = 0;j < surfacenumvertices;j++)
8165 RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
8166 numvertices += surfacenumvertices;
8167 numtriangles += surfacenumtriangles;
8170 // generate a 16bit index array as well if possible
8171 // (in general, dynamic batches fit)
8172 if (numvertices <= 65536)
8174 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
8175 for (i = 0;i < numtriangles*3;i++)
8176 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
8179 // since we've copied everything, the batch now starts at 0
8180 rsurface.batchfirstvertex = 0;
8181 rsurface.batchnumvertices = batchnumvertices;
8182 rsurface.batchfirsttriangle = 0;
8183 rsurface.batchnumtriangles = batchnumtriangles;
8186 // apply skeletal animation that would have been done in the vertex shader
8187 if (rsurface.batchskeletaltransform3x4)
8189 const unsigned char *si;
8190 const unsigned char *sw;
8192 const float *b = rsurface.batchskeletaltransform3x4;
8193 float *vp, *vs, *vt, *vn;
8195 float m[3][4], n[3][4];
8196 float tp[3], ts[3], tt[3], tn[3];
8197 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
8198 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
8199 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
8200 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
8201 si = rsurface.batchskeletalindex4ub;
8202 sw = rsurface.batchskeletalweight4ub;
8203 vp = rsurface.batchvertex3f;
8204 vs = rsurface.batchsvector3f;
8205 vt = rsurface.batchtvector3f;
8206 vn = rsurface.batchnormal3f;
8207 memset(m[0], 0, sizeof(m));
8208 memset(n[0], 0, sizeof(n));
8209 for (i = 0;i < batchnumvertices;i++)
8211 t[0] = b + si[0]*12;
8214 // common case - only one matrix
8228 else if (sw[2] + sw[3])
8231 t[1] = b + si[1]*12;
8232 t[2] = b + si[2]*12;
8233 t[3] = b + si[3]*12;
8234 w[0] = sw[0] * (1.0f / 255.0f);
8235 w[1] = sw[1] * (1.0f / 255.0f);
8236 w[2] = sw[2] * (1.0f / 255.0f);
8237 w[3] = sw[3] * (1.0f / 255.0f);
8238 // blend the matrices
8239 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
8240 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
8241 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
8242 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
8243 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
8244 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
8245 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
8246 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
8247 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
8248 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
8249 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
8250 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
8255 t[1] = b + si[1]*12;
8256 w[0] = sw[0] * (1.0f / 255.0f);
8257 w[1] = sw[1] * (1.0f / 255.0f);
8258 // blend the matrices
8259 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
8260 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
8261 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
8262 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
8263 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
8264 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
8265 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
8266 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
8267 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
8268 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
8269 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
8270 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
8274 // modify the vertex
8276 vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
8277 vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
8278 vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
8282 // the normal transformation matrix is a set of cross products...
8283 CrossProduct(m[1], m[2], n[0]);
8284 CrossProduct(m[2], m[0], n[1]);
8285 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8287 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8288 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8289 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8290 VectorNormalize(vn);
8295 vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8296 vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8297 vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8298 VectorNormalize(vs);
8301 vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8302 vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8303 vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8304 VectorNormalize(vt);
8309 rsurface.batchskeletaltransform3x4 = NULL;
8310 rsurface.batchskeletalnumtransforms = 0;
8313 // q1bsp surfaces rendered in vertex color mode have to have colors
8314 // calculated based on lightstyles
8315 if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo)
8317 // generate color arrays for the surfaces in this list
8322 const unsigned char *lm;
8323 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8324 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8325 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8327 for (i = 0;i < texturenumsurfaces;i++)
8329 surface = texturesurfacelist[i];
8330 offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8331 surfacenumvertices = surface->num_vertices;
8332 if (surface->lightmapinfo->samples)
8334 for (j = 0;j < surfacenumvertices;j++)
8336 lm = surface->lightmapinfo->samples + offsets[j];
8337 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8338 VectorScale(lm, scale, c);
8339 if (surface->lightmapinfo->styles[1] != 255)
8341 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8343 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8344 VectorMA(c, scale, lm, c);
8345 if (surface->lightmapinfo->styles[2] != 255)
8348 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8349 VectorMA(c, scale, lm, c);
8350 if (surface->lightmapinfo->styles[3] != 255)
8353 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8354 VectorMA(c, scale, lm, c);
8361 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);
8367 for (j = 0;j < surfacenumvertices;j++)
8369 Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8376 // if vertices are deformed (sprite flares and things in maps, possibly
8377 // water waves, bulges and other deformations), modify the copied vertices
8379 for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8382 switch (deform->deform)
8385 case Q3DEFORM_PROJECTIONSHADOW:
8386 case Q3DEFORM_TEXT0:
8387 case Q3DEFORM_TEXT1:
8388 case Q3DEFORM_TEXT2:
8389 case Q3DEFORM_TEXT3:
8390 case Q3DEFORM_TEXT4:
8391 case Q3DEFORM_TEXT5:
8392 case Q3DEFORM_TEXT6:
8393 case Q3DEFORM_TEXT7:
8396 case Q3DEFORM_AUTOSPRITE:
8397 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8398 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8399 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8400 VectorNormalize(newforward);
8401 VectorNormalize(newright);
8402 VectorNormalize(newup);
8403 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8404 // rsurface.batchvertex3f_vertexbuffer = NULL;
8405 // rsurface.batchvertex3f_bufferoffset = 0;
8406 // rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8407 // rsurface.batchsvector3f_vertexbuffer = NULL;
8408 // rsurface.batchsvector3f_bufferoffset = 0;
8409 // rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8410 // rsurface.batchtvector3f_vertexbuffer = NULL;
8411 // rsurface.batchtvector3f_bufferoffset = 0;
8412 // rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8413 // rsurface.batchnormal3f_vertexbuffer = NULL;
8414 // rsurface.batchnormal3f_bufferoffset = 0;
8415 // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8416 if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8417 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8418 if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8419 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);
8420 // a single autosprite surface can contain multiple sprites...
8421 for (j = 0;j < batchnumvertices - 3;j += 4)
8423 VectorClear(center);
8424 for (i = 0;i < 4;i++)
8425 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8426 VectorScale(center, 0.25f, center);
8427 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8428 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8429 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8430 for (i = 0;i < 4;i++)
8432 VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8433 VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8436 // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8437 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8438 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);
8440 case Q3DEFORM_AUTOSPRITE2:
8441 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8442 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8443 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8444 VectorNormalize(newforward);
8445 VectorNormalize(newright);
8446 VectorNormalize(newup);
8447 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8448 // rsurface.batchvertex3f_vertexbuffer = NULL;
8449 // rsurface.batchvertex3f_bufferoffset = 0;
8451 const float *v1, *v2;
8461 memset(shortest, 0, sizeof(shortest));
8462 // a single autosprite surface can contain multiple sprites...
8463 for (j = 0;j < batchnumvertices - 3;j += 4)
8465 VectorClear(center);
8466 for (i = 0;i < 4;i++)
8467 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8468 VectorScale(center, 0.25f, center);
8469 // find the two shortest edges, then use them to define the
8470 // axis vectors for rotating around the central axis
8471 for (i = 0;i < 6;i++)
8473 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8474 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8475 l = VectorDistance2(v1, v2);
8476 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8478 l += (1.0f / 1024.0f);
8479 if (shortest[0].length2 > l || i == 0)
8481 shortest[1] = shortest[0];
8482 shortest[0].length2 = l;
8483 shortest[0].v1 = v1;
8484 shortest[0].v2 = v2;
8486 else if (shortest[1].length2 > l || i == 1)
8488 shortest[1].length2 = l;
8489 shortest[1].v1 = v1;
8490 shortest[1].v2 = v2;
8493 VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8494 VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8495 // this calculates the right vector from the shortest edge
8496 // and the up vector from the edge midpoints
8497 VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8498 VectorNormalize(right);
8499 VectorSubtract(end, start, up);
8500 VectorNormalize(up);
8501 // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8502 VectorSubtract(rsurface.localvieworigin, center, forward);
8503 //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8504 VectorNegate(forward, forward);
8505 VectorReflect(forward, 0, up, forward);
8506 VectorNormalize(forward);
8507 CrossProduct(up, forward, newright);
8508 VectorNormalize(newright);
8509 // rotate the quad around the up axis vector, this is made
8510 // especially easy by the fact we know the quad is flat,
8511 // so we only have to subtract the center position and
8512 // measure distance along the right vector, and then
8513 // multiply that by the newright vector and add back the
8515 // we also need to subtract the old position to undo the
8516 // displacement from the center, which we do with a
8517 // DotProduct, the subtraction/addition of center is also
8518 // optimized into DotProducts here
8519 l = DotProduct(right, center);
8520 for (i = 0;i < 4;i++)
8522 v1 = rsurface.batchvertex3f + 3*(j+i);
8523 f = DotProduct(right, v1) - l;
8524 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8528 if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8530 // rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8531 // rsurface.batchnormal3f_vertexbuffer = NULL;
8532 // rsurface.batchnormal3f_bufferoffset = 0;
8533 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8535 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8537 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8538 // rsurface.batchsvector3f_vertexbuffer = NULL;
8539 // rsurface.batchsvector3f_bufferoffset = 0;
8540 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8541 // rsurface.batchtvector3f_vertexbuffer = NULL;
8542 // rsurface.batchtvector3f_bufferoffset = 0;
8543 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);
8546 case Q3DEFORM_NORMAL:
8547 // deform the normals to make reflections wavey
8548 rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8549 rsurface.batchnormal3f_vertexbuffer = NULL;
8550 rsurface.batchnormal3f_bufferoffset = 0;
8551 for (j = 0;j < batchnumvertices;j++)
8554 float *normal = rsurface.batchnormal3f + 3*j;
8555 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8556 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f( vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8557 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8558 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8559 VectorNormalize(normal);
8561 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8563 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8564 // rsurface.batchsvector3f_vertexbuffer = NULL;
8565 // rsurface.batchsvector3f_bufferoffset = 0;
8566 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8567 // rsurface.batchtvector3f_vertexbuffer = NULL;
8568 // rsurface.batchtvector3f_bufferoffset = 0;
8569 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);
8573 // deform vertex array to make wavey water and flags and such
8574 waveparms[0] = deform->waveparms[0];
8575 waveparms[1] = deform->waveparms[1];
8576 waveparms[2] = deform->waveparms[2];
8577 waveparms[3] = deform->waveparms[3];
8578 if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8579 break; // if wavefunc is a nop, don't make a dynamic vertex array
8580 // this is how a divisor of vertex influence on deformation
8581 animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8582 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8583 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8584 // rsurface.batchvertex3f_vertexbuffer = NULL;
8585 // rsurface.batchvertex3f_bufferoffset = 0;
8586 // rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8587 // rsurface.batchnormal3f_vertexbuffer = NULL;
8588 // rsurface.batchnormal3f_bufferoffset = 0;
8589 for (j = 0;j < batchnumvertices;j++)
8591 // if the wavefunc depends on time, evaluate it per-vertex
8594 waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8595 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8597 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8599 // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8600 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8601 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8603 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8604 // rsurface.batchsvector3f_vertexbuffer = NULL;
8605 // rsurface.batchsvector3f_bufferoffset = 0;
8606 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8607 // rsurface.batchtvector3f_vertexbuffer = NULL;
8608 // rsurface.batchtvector3f_bufferoffset = 0;
8609 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);
8612 case Q3DEFORM_BULGE:
8613 // deform vertex array to make the surface have moving bulges
8614 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8615 // rsurface.batchvertex3f_vertexbuffer = NULL;
8616 // rsurface.batchvertex3f_bufferoffset = 0;
8617 // rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8618 // rsurface.batchnormal3f_vertexbuffer = NULL;
8619 // rsurface.batchnormal3f_bufferoffset = 0;
8620 for (j = 0;j < batchnumvertices;j++)
8622 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8623 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8625 // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8626 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8627 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8629 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8630 // rsurface.batchsvector3f_vertexbuffer = NULL;
8631 // rsurface.batchsvector3f_bufferoffset = 0;
8632 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8633 // rsurface.batchtvector3f_vertexbuffer = NULL;
8634 // rsurface.batchtvector3f_bufferoffset = 0;
8635 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);
8639 // deform vertex array
8640 if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8641 break; // if wavefunc is a nop, don't make a dynamic vertex array
8642 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8643 VectorScale(deform->parms, scale, waveparms);
8644 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8645 // rsurface.batchvertex3f_vertexbuffer = NULL;
8646 // rsurface.batchvertex3f_bufferoffset = 0;
8647 for (j = 0;j < batchnumvertices;j++)
8648 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8653 if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8655 // generate texcoords based on the chosen texcoord source
8656 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8659 case Q3TCGEN_TEXTURE:
8661 case Q3TCGEN_LIGHTMAP:
8662 // rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8663 // rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8664 // rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8665 if (rsurface.batchtexcoordlightmap2f)
8666 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8668 case Q3TCGEN_VECTOR:
8669 // rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8670 // rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8671 // rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8672 for (j = 0;j < batchnumvertices;j++)
8674 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8675 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8678 case Q3TCGEN_ENVIRONMENT:
8679 // make environment reflections using a spheremap
8680 rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8681 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8682 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8683 for (j = 0;j < batchnumvertices;j++)
8685 // identical to Q3A's method, but executed in worldspace so
8686 // carried models can be shiny too
8688 float viewer[3], d, reflected[3], worldreflected[3];
8690 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8691 // VectorNormalize(viewer);
8693 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8695 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8696 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8697 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8698 // note: this is proportinal to viewer, so we can normalize later
8700 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8701 VectorNormalize(worldreflected);
8703 // note: this sphere map only uses world x and z!
8704 // so positive and negative y will LOOK THE SAME.
8705 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8706 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8710 // the only tcmod that needs software vertex processing is turbulent, so
8711 // check for it here and apply the changes if needed
8712 // and we only support that as the first one
8713 // (handling a mixture of turbulent and other tcmods would be problematic
8714 // without punting it entirely to a software path)
8715 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8717 amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8718 animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8719 // rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8720 // rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8721 // rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8722 for (j = 0;j < batchnumvertices;j++)
8724 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);
8725 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1] ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8730 if (needsupdate & batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP))
8732 // convert the modified arrays to vertex structs
8733 // rsurface.batchvertexmesh = R_FrameData_Alloc(batchnumvertices * sizeof(r_vertexmesh_t));
8734 // rsurface.batchvertexmesh_vertexbuffer = NULL;
8735 // rsurface.batchvertexmesh_bufferoffset = 0;
8736 if (batchneed & BATCHNEED_VERTEXMESH_VERTEX)
8737 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8738 VectorCopy(rsurface.batchvertex3f + 3*j, vertexmesh->vertex3f);
8739 if (batchneed & BATCHNEED_VERTEXMESH_NORMAL)
8740 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8741 VectorCopy(rsurface.batchnormal3f + 3*j, vertexmesh->normal3f);
8742 if (batchneed & BATCHNEED_VERTEXMESH_VECTOR)
8744 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8746 VectorCopy(rsurface.batchsvector3f + 3*j, vertexmesh->svector3f);
8747 VectorCopy(rsurface.batchtvector3f + 3*j, vertexmesh->tvector3f);
8750 if ((batchneed & BATCHNEED_VERTEXMESH_VERTEXCOLOR) && rsurface.batchlightmapcolor4f)
8751 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8752 Vector4Copy(rsurface.batchlightmapcolor4f + 4*j, vertexmesh->color4f);
8753 if (batchneed & BATCHNEED_VERTEXMESH_TEXCOORD)
8754 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8755 Vector2Copy(rsurface.batchtexcoordtexture2f + 2*j, vertexmesh->texcoordtexture2f);
8756 if ((batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP) && rsurface.batchtexcoordlightmap2f)
8757 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8758 Vector2Copy(rsurface.batchtexcoordlightmap2f + 2*j, vertexmesh->texcoordlightmap2f);
8759 if ((batchneed & BATCHNEED_VERTEXMESH_SKELETAL) && rsurface.batchskeletalindex4ub)
8761 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8763 Vector4Copy(rsurface.batchskeletalindex4ub + 4*j, vertexmesh->skeletalindex4ub);
8764 Vector4Copy(rsurface.batchskeletalweight4ub + 4*j, vertexmesh->skeletalweight4ub);
8769 // upload buffer data for the dynamic batch
8770 if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicvertex.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo)
8772 if (rsurface.batchvertexmesh)
8773 rsurface.batchvertexmesh_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(r_vertexmesh_t), rsurface.batchvertexmesh, R_BUFFERDATA_VERTEX, &rsurface.batchvertexmesh_bufferoffset);
8776 if (rsurface.batchvertex3f)
8777 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
8778 if (rsurface.batchsvector3f)
8779 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
8780 if (rsurface.batchtvector3f)
8781 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
8782 if (rsurface.batchnormal3f)
8783 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
8784 if (rsurface.batchlightmapcolor4f)
8785 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
8786 if (rsurface.batchtexcoordtexture2f)
8787 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
8788 if (rsurface.batchtexcoordlightmap2f)
8789 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
8790 if (rsurface.batchskeletalindex4ub)
8791 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
8792 if (rsurface.batchskeletalweight4ub)
8793 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
8795 if (rsurface.batchelement3s)
8796 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
8797 else if (rsurface.batchelement3i)
8798 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
8802 void RSurf_DrawBatch(void)
8804 // sometimes a zero triangle surface (usually a degenerate patch) makes it
8805 // through the pipeline, killing it earlier in the pipeline would have
8806 // per-surface overhead rather than per-batch overhead, so it's best to
8807 // reject it here, before it hits glDraw.
8808 if (rsurface.batchnumtriangles == 0)
8811 // batch debugging code
8812 if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8818 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8819 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8822 for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8824 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8826 if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8827 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);
8834 if (rsurface.batchmultidraw)
8836 // issue multiple draws rather than copying index data
8837 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8838 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8839 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8840 for (i = 0;i < numsurfaces;)
8842 // combine consecutive surfaces as one draw
8843 for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8844 if (surfacelist[j] != surfacelist[k] + 1)
8846 firstvertex = surfacelist[i]->num_firstvertex;
8847 endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8848 firsttriangle = surfacelist[i]->num_firsttriangle;
8849 endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8850 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);
8856 // there is only one consecutive run of index data (may have been combined)
8857 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);
8861 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8863 // pick the closest matching water plane
8864 int planeindex, vertexindex, bestplaneindex = -1;
8868 r_waterstate_waterplane_t *p;
8869 qboolean prepared = false;
8871 for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8873 if(p->camera_entity != rsurface.texture->camera_entity)
8878 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8880 if(rsurface.batchnumvertices == 0)
8883 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8885 Matrix4x4_Transform(&rsurface.matrix, v, vert);
8886 d += fabs(PlaneDiff(vert, &p->plane));
8888 if (bestd > d || bestplaneindex < 0)
8891 bestplaneindex = planeindex;
8894 return bestplaneindex;
8895 // NOTE: this MAY return a totally unrelated water plane; we can ignore
8896 // this situation though, as it might be better to render single larger
8897 // batches with useless stuff (backface culled for example) than to
8898 // render multiple smaller batches
8901 void RSurf_SetupDepthAndCulling(void)
8903 // submodels are biased to avoid z-fighting with world surfaces that they
8904 // may be exactly overlapping (avoids z-fighting artifacts on certain
8905 // doors and things in Quake maps)
8906 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8907 GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8908 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8909 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8912 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8915 // transparent sky would be ridiculous
8916 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8918 R_SetupShader_Generic_NoTexture(false, false);
8919 skyrenderlater = true;
8920 RSurf_SetupDepthAndCulling();
8923 // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8924 if (r_sky_scissor.integer)
8926 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8927 for (i = 0; i < texturenumsurfaces; i++)
8929 const msurface_t *surf = texturesurfacelist[i];
8932 float mins[3], maxs[3];
8934 for (j = 0, v = rsurface.batchvertex3f + 3 * surf->num_firstvertex; j < surf->num_vertices; j++, v += 3)
8936 Matrix4x4_Transform(&rsurface.matrix, v, p);
8939 if (mins[0] > p[0]) mins[0] = p[0];
8940 if (mins[1] > p[1]) mins[1] = p[1];
8941 if (mins[2] > p[2]) mins[2] = p[2];
8942 if (maxs[0] < p[0]) maxs[0] = p[0];
8943 if (maxs[1] < p[1]) maxs[1] = p[1];
8944 if (maxs[2] < p[2]) maxs[2] = p[2];
8948 VectorCopy(p, mins);
8949 VectorCopy(p, maxs);
8952 if (!R_ScissorForBBox(mins, maxs, scissor))
8956 if (skyscissor[0] > scissor[0])
8958 skyscissor[2] += skyscissor[0] - scissor[0];
8959 skyscissor[0] = scissor[0];
8961 if (skyscissor[1] > scissor[1])
8963 skyscissor[3] += skyscissor[1] - scissor[1];
8964 skyscissor[1] = scissor[1];
8966 if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8967 skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8968 if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8969 skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8972 Vector4Copy(scissor, skyscissor);
8977 // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8978 // skymasking on them, and Quake3 never did sky masking (unlike
8979 // software Quake and software Quake2), so disable the sky masking
8980 // in Quake3 maps as it causes problems with q3map2 sky tricks,
8981 // and skymasking also looks very bad when noclipping outside the
8982 // level, so don't use it then either.
8983 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)
8985 R_Mesh_ResetTextureState();
8986 if (skyrendermasked)
8988 R_SetupShader_DepthOrShadow(false, false, false);
8989 // depth-only (masking)
8990 GL_ColorMask(0, 0, 0, 0);
8991 // just to make sure that braindead drivers don't draw
8992 // anything despite that colormask...
8993 GL_BlendFunc(GL_ZERO, GL_ONE);
8994 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8995 R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8999 R_SetupShader_Generic_NoTexture(false, false);
9001 GL_BlendFunc(GL_ONE, GL_ZERO);
9002 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9003 GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
9004 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9007 if (skyrendermasked)
9008 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
9010 R_Mesh_ResetTextureState();
9011 GL_Color(1, 1, 1, 1);
9014 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
9015 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
9016 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
9018 if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
9022 // render screenspace normalmap to texture
9024 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false);
9029 // bind lightmap texture
9031 // water/refraction/reflection/camera surfaces have to be handled specially
9032 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
9034 int start, end, startplaneindex;
9035 for (start = 0;start < texturenumsurfaces;start = end)
9037 startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
9038 if(startplaneindex < 0)
9040 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
9041 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
9045 for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
9047 // now that we have a batch using the same planeindex, render it
9048 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
9050 // render water or distortion background
9052 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
9054 // blend surface on top
9055 GL_DepthMask(false);
9056 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false);
9059 else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
9061 // render surface with reflection texture as input
9062 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
9063 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
9070 // render surface batch normally
9071 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
9072 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0);
9076 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
9080 r_vertexgeneric_t *batchvertex;
9082 texture_t *t = rsurface.texture;
9084 // R_Mesh_ResetTextureState();
9085 R_SetupShader_Generic_NoTexture(false, false);
9087 if(t && t->currentskinframe)
9089 memcpy(c, t->currentskinframe->avgcolor, sizeof(c));
9090 c[3] *= t->currentalpha;
9100 if (t->pantstexture || t->shirttexture)
9102 c[0] = 0.5 * (t->render_colormap_pants[0] * 0.3 + t->render_colormap_shirt[0] * 0.7);
9103 c[1] = 0.5 * (t->render_colormap_pants[1] * 0.3 + t->render_colormap_shirt[1] * 0.7);
9104 c[2] = 0.5 * (t->render_colormap_pants[2] * 0.3 + t->render_colormap_shirt[2] * 0.7);
9107 // brighten it up (as texture value 127 means "unlit")
9108 c[0] *= 2 * r_refdef.view.colorscale;
9109 c[1] *= 2 * r_refdef.view.colorscale;
9110 c[2] *= 2 * r_refdef.view.colorscale;
9112 if(t->currentmaterialflags & MATERIALFLAG_WATERALPHA)
9113 c[3] *= r_wateralpha.value;
9115 if(t->currentmaterialflags & MATERIALFLAG_ALPHA && c[3] != 1)
9117 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9118 GL_DepthMask(false);
9120 else if(t->currentmaterialflags & MATERIALFLAG_ADD)
9122 GL_BlendFunc(GL_ONE, GL_ONE);
9123 GL_DepthMask(false);
9125 else if(t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
9127 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // can't do alpha test without texture, so let's blend instead
9128 GL_DepthMask(false);
9130 else if(t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
9132 GL_BlendFunc(t->customblendfunc[0], t->customblendfunc[1]);
9133 GL_DepthMask(false);
9137 GL_BlendFunc(GL_ONE, GL_ZERO);
9138 GL_DepthMask(writedepth);
9141 if (!r_refdef.view.showdebug)
9143 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9144 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices);
9145 for (j = 0, vi = 0;j < rsurface.batchnumvertices;j++, vi++)
9147 VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
9148 Vector4Set(batchvertex[vi].color4f, 0, 0, 0, 1);
9150 R_Mesh_PrepareVertices_Generic_Unlock();
9153 else if (r_showsurfaces.integer == 4)
9155 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9156 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices);
9157 for (j = 0, vi = 0;j < rsurface.batchnumvertices;j++, vi++)
9159 float d = (vi << 3) * (1.0f / 256.0f);
9160 VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
9161 Vector4Set(batchvertex[vi].color4f, d, d, d, 1);
9163 R_Mesh_PrepareVertices_Generic_Unlock();
9166 else if (r_showsurfaces.integer == 2)
9169 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9170 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(3*rsurface.batchnumtriangles);
9171 for (j = 0, e = rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle;j < rsurface.batchnumtriangles;j++, e += 3)
9173 float d = ((j + rsurface.batchfirsttriangle) << 3) * (1.0f / 256.0f);
9174 VectorCopy(rsurface.batchvertex3f + 3*e[0], batchvertex[j*3+0].vertex3f);
9175 VectorCopy(rsurface.batchvertex3f + 3*e[1], batchvertex[j*3+1].vertex3f);
9176 VectorCopy(rsurface.batchvertex3f + 3*e[2], batchvertex[j*3+2].vertex3f);
9177 Vector4Set(batchvertex[j*3+0].color4f, d, d, d, 1);
9178 Vector4Set(batchvertex[j*3+1].color4f, d, d, d, 1);
9179 Vector4Set(batchvertex[j*3+2].color4f, d, d, d, 1);
9181 R_Mesh_PrepareVertices_Generic_Unlock();
9182 R_Mesh_Draw(0, rsurface.batchnumtriangles*3, 0, rsurface.batchnumtriangles, NULL, NULL, 0, NULL, NULL, 0);
9186 int texturesurfaceindex;
9188 const msurface_t *surface;
9189 float surfacecolor4f[4];
9190 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9191 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchfirstvertex + rsurface.batchnumvertices);
9193 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
9195 surface = texturesurfacelist[texturesurfaceindex];
9196 k = (int)(((size_t)surface) / sizeof(msurface_t));
9197 Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
9198 for (j = 0;j < surface->num_vertices;j++)
9200 VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
9201 Vector4Copy(surfacecolor4f, batchvertex[vi].color4f);
9205 R_Mesh_PrepareVertices_Generic_Unlock();
9210 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
9213 RSurf_SetupDepthAndCulling();
9214 if (r_showsurfaces.integer)
9216 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
9219 switch (vid.renderpath)
9221 case RENDERPATH_GL20:
9222 case RENDERPATH_GLES2:
9223 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
9229 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9232 int texturenumsurfaces, endsurface;
9234 const msurface_t *surface;
9235 const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
9237 RSurf_ActiveModelEntity(ent, true, true, false);
9239 if (r_transparentdepthmasking.integer)
9241 qboolean setup = false;
9242 for (i = 0;i < numsurfaces;i = j)
9245 surface = rsurface.modelsurfaces + surfacelist[i];
9246 texture = surface->texture;
9247 rsurface.texture = R_GetCurrentTexture(texture);
9248 rsurface.lightmaptexture = NULL;
9249 rsurface.deluxemaptexture = NULL;
9250 rsurface.uselightmaptexture = false;
9251 // scan ahead until we find a different texture
9252 endsurface = min(i + 1024, numsurfaces);
9253 texturenumsurfaces = 0;
9254 texturesurfacelist[texturenumsurfaces++] = surface;
9255 for (;j < endsurface;j++)
9257 surface = rsurface.modelsurfaces + surfacelist[j];
9258 if (texture != surface->texture)
9260 texturesurfacelist[texturenumsurfaces++] = surface;
9262 if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
9264 // render the range of surfaces as depth
9268 GL_ColorMask(0,0,0,0);
9271 GL_BlendFunc(GL_ONE, GL_ZERO);
9273 // R_Mesh_ResetTextureState();
9275 RSurf_SetupDepthAndCulling();
9276 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9277 R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9278 R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9282 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
9285 for (i = 0;i < numsurfaces;i = j)
9288 surface = rsurface.modelsurfaces + surfacelist[i];
9289 texture = surface->texture;
9290 rsurface.texture = R_GetCurrentTexture(texture);
9291 // scan ahead until we find a different texture
9292 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
9293 texturenumsurfaces = 0;
9294 texturesurfacelist[texturenumsurfaces++] = surface;
9295 if(FAKELIGHT_ENABLED)
9297 rsurface.lightmaptexture = NULL;
9298 rsurface.deluxemaptexture = NULL;
9299 rsurface.uselightmaptexture = false;
9300 for (;j < endsurface;j++)
9302 surface = rsurface.modelsurfaces + surfacelist[j];
9303 if (texture != surface->texture)
9305 texturesurfacelist[texturenumsurfaces++] = surface;
9310 rsurface.lightmaptexture = surface->lightmaptexture;
9311 rsurface.deluxemaptexture = surface->deluxemaptexture;
9312 rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
9313 for (;j < endsurface;j++)
9315 surface = rsurface.modelsurfaces + surfacelist[j];
9316 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
9318 texturesurfacelist[texturenumsurfaces++] = surface;
9321 // render the range of surfaces
9322 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false);
9324 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
9327 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9329 // transparent surfaces get pushed off into the transparent queue
9330 int surfacelistindex;
9331 const msurface_t *surface;
9332 vec3_t tempcenter, center;
9333 for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
9335 surface = texturesurfacelist[surfacelistindex];
9336 if (r_transparent_sortsurfacesbynearest.integer)
9338 tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
9339 tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
9340 tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
9344 tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
9345 tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
9346 tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
9348 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
9349 if (rsurface.entity->transparent_offset) // transparent offset
9351 center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
9352 center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
9353 center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
9355 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);
9359 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9361 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
9363 if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
9365 RSurf_SetupDepthAndCulling();
9366 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9367 R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9368 R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9372 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass)
9376 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
9379 if (!rsurface.texture->currentnumlayers)
9381 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
9382 R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9384 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
9386 else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
9387 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
9388 else if (!rsurface.texture->currentnumlayers)
9390 else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
9392 // in the deferred case, transparent surfaces were queued during prepass
9393 if (!r_shadow_usingdeferredprepass)
9394 R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9398 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
9399 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass);
9404 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass)
9408 R_FrameData_SetMark();
9409 // break the surface list down into batches by texture and use of lightmapping
9410 for (i = 0;i < numsurfaces;i = j)
9413 // texture is the base texture pointer, rsurface.texture is the
9414 // current frame/skin the texture is directing us to use (for example
9415 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
9416 // use skin 1 instead)
9417 texture = surfacelist[i]->texture;
9418 rsurface.texture = R_GetCurrentTexture(texture);
9419 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
9421 // if this texture is not the kind we want, skip ahead to the next one
9422 for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9426 if(FAKELIGHT_ENABLED || depthonly || prepass)
9428 rsurface.lightmaptexture = NULL;
9429 rsurface.deluxemaptexture = NULL;
9430 rsurface.uselightmaptexture = false;
9431 // simply scan ahead until we find a different texture or lightmap state
9432 for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9437 rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
9438 rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
9439 rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
9440 // simply scan ahead until we find a different texture or lightmap state
9441 for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
9444 // render the range of surfaces
9445 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass);
9447 R_FrameData_ReturnToMark();
9450 float locboxvertex3f[6*4*3] =
9452 1,0,1, 1,0,0, 1,1,0, 1,1,1,
9453 0,1,1, 0,1,0, 0,0,0, 0,0,1,
9454 1,1,1, 1,1,0, 0,1,0, 0,1,1,
9455 0,0,1, 0,0,0, 1,0,0, 1,0,1,
9456 0,0,1, 1,0,1, 1,1,1, 0,1,1,
9457 1,0,0, 0,0,0, 0,1,0, 1,1,0
9460 unsigned short locboxelements[6*2*3] =
9470 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9473 cl_locnode_t *loc = (cl_locnode_t *)ent;
9475 float vertex3f[6*4*3];
9477 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9478 GL_DepthMask(false);
9479 GL_DepthRange(0, 1);
9480 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9482 GL_CullFace(GL_NONE);
9483 R_EntityMatrix(&identitymatrix);
9485 // R_Mesh_ResetTextureState();
9488 GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9489 ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9490 ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9491 surfacelist[0] < 0 ? 0.5f : 0.125f);
9493 if (VectorCompare(loc->mins, loc->maxs))
9495 VectorSet(size, 2, 2, 2);
9496 VectorMA(loc->mins, -0.5f, size, mins);
9500 VectorCopy(loc->mins, mins);
9501 VectorSubtract(loc->maxs, loc->mins, size);
9504 for (i = 0;i < 6*4*3;)
9505 for (j = 0;j < 3;j++, i++)
9506 vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9508 R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9509 R_SetupShader_Generic_NoTexture(false, false);
9510 R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9513 void R_DrawLocs(void)
9516 cl_locnode_t *loc, *nearestloc;
9518 nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9519 for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9521 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9522 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9526 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9528 if (decalsystem->decals)
9529 Mem_Free(decalsystem->decals);
9530 memset(decalsystem, 0, sizeof(*decalsystem));
9533 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)
9539 // expand or initialize the system
9540 if (decalsystem->maxdecals <= decalsystem->numdecals)
9542 decalsystem_t old = *decalsystem;
9543 qboolean useshortelements;
9544 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9545 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9546 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)));
9547 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9548 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9549 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9550 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9551 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9552 if (decalsystem->numdecals)
9553 memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9555 Mem_Free(old.decals);
9556 for (i = 0;i < decalsystem->maxdecals*3;i++)
9557 decalsystem->element3i[i] = i;
9558 if (useshortelements)
9559 for (i = 0;i < decalsystem->maxdecals*3;i++)
9560 decalsystem->element3s[i] = i;
9563 // grab a decal and search for another free slot for the next one
9564 decals = decalsystem->decals;
9565 decal = decalsystem->decals + (i = decalsystem->freedecal++);
9566 for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9568 decalsystem->freedecal = i;
9569 if (decalsystem->numdecals <= i)
9570 decalsystem->numdecals = i + 1;
9572 // initialize the decal
9574 decal->triangleindex = triangleindex;
9575 decal->surfaceindex = surfaceindex;
9576 decal->decalsequence = decalsequence;
9577 decal->color4f[0][0] = c0[0];
9578 decal->color4f[0][1] = c0[1];
9579 decal->color4f[0][2] = c0[2];
9580 decal->color4f[0][3] = 1;
9581 decal->color4f[1][0] = c1[0];
9582 decal->color4f[1][1] = c1[1];
9583 decal->color4f[1][2] = c1[2];
9584 decal->color4f[1][3] = 1;
9585 decal->color4f[2][0] = c2[0];
9586 decal->color4f[2][1] = c2[1];
9587 decal->color4f[2][2] = c2[2];
9588 decal->color4f[2][3] = 1;
9589 decal->vertex3f[0][0] = v0[0];
9590 decal->vertex3f[0][1] = v0[1];
9591 decal->vertex3f[0][2] = v0[2];
9592 decal->vertex3f[1][0] = v1[0];
9593 decal->vertex3f[1][1] = v1[1];
9594 decal->vertex3f[1][2] = v1[2];
9595 decal->vertex3f[2][0] = v2[0];
9596 decal->vertex3f[2][1] = v2[1];
9597 decal->vertex3f[2][2] = v2[2];
9598 decal->texcoord2f[0][0] = t0[0];
9599 decal->texcoord2f[0][1] = t0[1];
9600 decal->texcoord2f[1][0] = t1[0];
9601 decal->texcoord2f[1][1] = t1[1];
9602 decal->texcoord2f[2][0] = t2[0];
9603 decal->texcoord2f[2][1] = t2[1];
9604 TriangleNormal(v0, v1, v2, decal->plane);
9605 VectorNormalize(decal->plane);
9606 decal->plane[3] = DotProduct(v0, decal->plane);
9609 extern cvar_t cl_decals_bias;
9610 extern cvar_t cl_decals_models;
9611 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9612 // baseparms, parms, temps
9613 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)
9618 const float *vertex3f;
9619 const float *normal3f;
9621 float points[2][9][3];
9628 e = rsurface.modelelement3i + 3*triangleindex;
9630 vertex3f = rsurface.modelvertex3f;
9631 normal3f = rsurface.modelnormal3f;
9635 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9637 index = 3*e[cornerindex];
9638 VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9643 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9645 index = 3*e[cornerindex];
9646 VectorCopy(vertex3f + index, v[cornerindex]);
9651 //TriangleNormal(v[0], v[1], v[2], normal);
9652 //if (DotProduct(normal, localnormal) < 0.0f)
9654 // clip by each of the box planes formed from the projection matrix
9655 // if anything survives, we emit the decal
9656 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]);
9659 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]);
9662 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]);
9665 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]);
9668 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]);
9671 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]);
9674 // some part of the triangle survived, so we have to accept it...
9677 // dynamic always uses the original triangle
9679 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9681 index = 3*e[cornerindex];
9682 VectorCopy(vertex3f + index, v[cornerindex]);
9685 for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9687 // convert vertex positions to texcoords
9688 Matrix4x4_Transform(projection, v[cornerindex], temp);
9689 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9690 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9691 // calculate distance fade from the projection origin
9692 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9693 f = bound(0.0f, f, 1.0f);
9694 c[cornerindex][0] = r * f;
9695 c[cornerindex][1] = g * f;
9696 c[cornerindex][2] = b * f;
9697 c[cornerindex][3] = 1.0f;
9698 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9701 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);
9703 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9704 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);
9706 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)
9708 matrix4x4_t projection;
9709 decalsystem_t *decalsystem;
9712 const msurface_t *surface;
9713 const msurface_t *surfaces;
9714 const int *surfacelist;
9715 const texture_t *texture;
9718 int surfacelistindex;
9721 float localorigin[3];
9722 float localnormal[3];
9730 int bih_triangles_count;
9731 int bih_triangles[256];
9732 int bih_surfaces[256];
9734 decalsystem = &ent->decalsystem;
9736 if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9738 R_DecalSystem_Reset(&ent->decalsystem);
9742 if (!model->brush.data_leafs && !cl_decals_models.integer)
9744 if (decalsystem->model)
9745 R_DecalSystem_Reset(decalsystem);
9749 if (decalsystem->model != model)
9750 R_DecalSystem_Reset(decalsystem);
9751 decalsystem->model = model;
9753 RSurf_ActiveModelEntity(ent, true, false, false);
9755 Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9756 Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9757 VectorNormalize(localnormal);
9758 localsize = worldsize*rsurface.inversematrixscale;
9759 localmins[0] = localorigin[0] - localsize;
9760 localmins[1] = localorigin[1] - localsize;
9761 localmins[2] = localorigin[2] - localsize;
9762 localmaxs[0] = localorigin[0] + localsize;
9763 localmaxs[1] = localorigin[1] + localsize;
9764 localmaxs[2] = localorigin[2] + localsize;
9766 //VectorCopy(localnormal, planes[4]);
9767 //VectorVectors(planes[4], planes[2], planes[0]);
9768 AnglesFromVectors(angles, localnormal, NULL, false);
9769 AngleVectors(angles, planes[0], planes[2], planes[4]);
9770 VectorNegate(planes[0], planes[1]);
9771 VectorNegate(planes[2], planes[3]);
9772 VectorNegate(planes[4], planes[5]);
9773 planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9774 planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9775 planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9776 planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9777 planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9778 planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9783 matrix4x4_t forwardprojection;
9784 Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9785 Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9790 float projectionvector[4][3];
9791 VectorScale(planes[0], ilocalsize, projectionvector[0]);
9792 VectorScale(planes[2], ilocalsize, projectionvector[1]);
9793 VectorScale(planes[4], ilocalsize, projectionvector[2]);
9794 projectionvector[0][0] = planes[0][0] * ilocalsize;
9795 projectionvector[0][1] = planes[1][0] * ilocalsize;
9796 projectionvector[0][2] = planes[2][0] * ilocalsize;
9797 projectionvector[1][0] = planes[0][1] * ilocalsize;
9798 projectionvector[1][1] = planes[1][1] * ilocalsize;
9799 projectionvector[1][2] = planes[2][1] * ilocalsize;
9800 projectionvector[2][0] = planes[0][2] * ilocalsize;
9801 projectionvector[2][1] = planes[1][2] * ilocalsize;
9802 projectionvector[2][2] = planes[2][2] * ilocalsize;
9803 projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9804 projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9805 projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9806 Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9810 dynamic = model->surfmesh.isanimated;
9811 numsurfacelist = model->nummodelsurfaces;
9812 surfacelist = model->sortedmodelsurfaces;
9813 surfaces = model->data_surfaces;
9816 bih_triangles_count = -1;
9819 if(model->render_bih.numleafs)
9820 bih = &model->render_bih;
9821 else if(model->collision_bih.numleafs)
9822 bih = &model->collision_bih;
9825 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9826 if(bih_triangles_count == 0)
9828 if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9830 if(bih_triangles_count > 0)
9832 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9834 surfaceindex = bih_surfaces[triangleindex];
9835 surface = surfaces + surfaceindex;
9836 texture = surface->texture;
9837 if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9839 if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9841 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9846 for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
9848 surfaceindex = surfacelist[surfacelistindex];
9849 surface = surfaces + surfaceindex;
9850 // check cull box first because it rejects more than any other check
9851 if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9853 // skip transparent surfaces
9854 texture = surface->texture;
9855 if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9857 if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9859 numtriangles = surface->num_triangles;
9860 for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9861 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9866 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9867 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)
9869 int renderentityindex;
9872 entity_render_t *ent;
9874 if (!cl_decals_newsystem.integer)
9877 worldmins[0] = worldorigin[0] - worldsize;
9878 worldmins[1] = worldorigin[1] - worldsize;
9879 worldmins[2] = worldorigin[2] - worldsize;
9880 worldmaxs[0] = worldorigin[0] + worldsize;
9881 worldmaxs[1] = worldorigin[1] + worldsize;
9882 worldmaxs[2] = worldorigin[2] + worldsize;
9884 R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9886 for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9888 ent = r_refdef.scene.entities[renderentityindex];
9889 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9892 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9896 typedef struct r_decalsystem_splatqueue_s
9903 unsigned int decalsequence;
9905 r_decalsystem_splatqueue_t;
9907 int r_decalsystem_numqueued = 0;
9908 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9910 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)
9912 r_decalsystem_splatqueue_t *queue;
9914 if (!cl_decals_newsystem.integer || r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9917 queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9918 VectorCopy(worldorigin, queue->worldorigin);
9919 VectorCopy(worldnormal, queue->worldnormal);
9920 Vector4Set(queue->color, r, g, b, a);
9921 Vector4Set(queue->tcrange, s1, t1, s2, t2);
9922 queue->worldsize = worldsize;
9923 queue->decalsequence = cl.decalsequence++;
9926 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9929 r_decalsystem_splatqueue_t *queue;
9931 for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9932 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);
9933 r_decalsystem_numqueued = 0;
9936 extern cvar_t cl_decals_max;
9937 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9940 decalsystem_t *decalsystem = &ent->decalsystem;
9942 unsigned int killsequence;
9947 if (!decalsystem->numdecals)
9950 if (r_showsurfaces.integer)
9953 if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9955 R_DecalSystem_Reset(decalsystem);
9959 killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9960 lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9962 if (decalsystem->lastupdatetime)
9963 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9966 decalsystem->lastupdatetime = r_refdef.scene.time;
9967 numdecals = decalsystem->numdecals;
9969 for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9971 if (decal->color4f[0][3])
9973 decal->lived += frametime;
9974 if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9976 memset(decal, 0, sizeof(*decal));
9977 if (decalsystem->freedecal > i)
9978 decalsystem->freedecal = i;
9982 decal = decalsystem->decals;
9983 while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9986 // collapse the array by shuffling the tail decals into the gaps
9989 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
9990 decalsystem->freedecal++;
9991 if (decalsystem->freedecal == numdecals)
9993 decal[decalsystem->freedecal] = decal[--numdecals];
9996 decalsystem->numdecals = numdecals;
10000 // if there are no decals left, reset decalsystem
10001 R_DecalSystem_Reset(decalsystem);
10005 extern skinframe_t *decalskinframe;
10006 static void R_DrawModelDecals_Entity(entity_render_t *ent)
10009 decalsystem_t *decalsystem = &ent->decalsystem;
10018 const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
10021 numdecals = decalsystem->numdecals;
10025 if (r_showsurfaces.integer)
10028 if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
10030 R_DecalSystem_Reset(decalsystem);
10034 // if the model is static it doesn't matter what value we give for
10035 // wantnormals and wanttangents, so this logic uses only rules applicable
10036 // to a model, knowing that they are meaningless otherwise
10037 RSurf_ActiveModelEntity(ent, false, false, false);
10039 decalsystem->lastupdatetime = r_refdef.scene.time;
10041 faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
10043 // update vertex positions for animated models
10044 v3f = decalsystem->vertex3f;
10045 c4f = decalsystem->color4f;
10046 t2f = decalsystem->texcoord2f;
10047 for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
10049 if (!decal->color4f[0][3])
10052 if (surfacevisible && !surfacevisible[decal->surfaceindex])
10056 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
10059 // update color values for fading decals
10060 if (decal->lived >= cl_decals_time.value)
10061 alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
10065 c4f[ 0] = decal->color4f[0][0] * alpha;
10066 c4f[ 1] = decal->color4f[0][1] * alpha;
10067 c4f[ 2] = decal->color4f[0][2] * alpha;
10069 c4f[ 4] = decal->color4f[1][0] * alpha;
10070 c4f[ 5] = decal->color4f[1][1] * alpha;
10071 c4f[ 6] = decal->color4f[1][2] * alpha;
10073 c4f[ 8] = decal->color4f[2][0] * alpha;
10074 c4f[ 9] = decal->color4f[2][1] * alpha;
10075 c4f[10] = decal->color4f[2][2] * alpha;
10078 t2f[0] = decal->texcoord2f[0][0];
10079 t2f[1] = decal->texcoord2f[0][1];
10080 t2f[2] = decal->texcoord2f[1][0];
10081 t2f[3] = decal->texcoord2f[1][1];
10082 t2f[4] = decal->texcoord2f[2][0];
10083 t2f[5] = decal->texcoord2f[2][1];
10085 // update vertex positions for animated models
10086 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
10088 e = rsurface.modelelement3i + 3*decal->triangleindex;
10089 VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
10090 VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
10091 VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
10095 VectorCopy(decal->vertex3f[0], v3f);
10096 VectorCopy(decal->vertex3f[1], v3f + 3);
10097 VectorCopy(decal->vertex3f[2], v3f + 6);
10100 if (r_refdef.fogenabled)
10102 alpha = RSurf_FogVertex(v3f);
10103 VectorScale(c4f, alpha, c4f);
10104 alpha = RSurf_FogVertex(v3f + 3);
10105 VectorScale(c4f + 4, alpha, c4f + 4);
10106 alpha = RSurf_FogVertex(v3f + 6);
10107 VectorScale(c4f + 8, alpha, c4f + 8);
10118 r_refdef.stats[r_stat_drawndecals] += numtris;
10120 // now render the decals all at once
10121 // (this assumes they all use one particle font texture!)
10122 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);
10123 // R_Mesh_ResetTextureState();
10124 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
10125 GL_DepthMask(false);
10126 GL_DepthRange(0, 1);
10127 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
10128 GL_DepthTest(true);
10129 GL_CullFace(GL_NONE);
10130 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
10131 R_SetupShader_Generic(decalskinframe->base, NULL, GL_MODULATE, 1, false, false, false);
10132 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
10136 static void R_DrawModelDecals(void)
10140 // fade faster when there are too many decals
10141 numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
10142 for (i = 0;i < r_refdef.scene.numentities;i++)
10143 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
10145 R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
10146 for (i = 0;i < r_refdef.scene.numentities;i++)
10147 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
10148 R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
10150 R_DecalSystem_ApplySplatEntitiesQueue();
10152 numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
10153 for (i = 0;i < r_refdef.scene.numentities;i++)
10154 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
10156 r_refdef.stats[r_stat_totaldecals] += numdecals;
10158 if (r_showsurfaces.integer)
10161 R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
10163 for (i = 0;i < r_refdef.scene.numentities;i++)
10165 if (!r_refdef.viewcache.entityvisible[i])
10167 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
10168 R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
10172 extern cvar_t mod_collision_bih;
10173 static void R_DrawDebugModel(void)
10175 entity_render_t *ent = rsurface.entity;
10176 int i, j, flagsmask;
10177 const msurface_t *surface;
10178 dp_model_t *model = ent->model;
10180 if (!sv.active && !cls.demoplayback && ent != r_refdef.scene.worldentity)
10183 if (r_showoverdraw.value > 0)
10185 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
10186 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
10187 R_SetupShader_Generic_NoTexture(false, false);
10188 GL_DepthTest(false);
10189 GL_DepthMask(false);
10190 GL_DepthRange(0, 1);
10191 GL_BlendFunc(GL_ONE, GL_ONE);
10192 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10194 if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10196 rsurface.texture = R_GetCurrentTexture(surface->texture);
10197 if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10199 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
10200 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
10201 if (!rsurface.texture->currentlayers->depthmask)
10202 GL_Color(c, 0, 0, 1.0f);
10203 else if (ent == r_refdef.scene.worldentity)
10204 GL_Color(c, c, c, 1.0f);
10206 GL_Color(0, c, 0, 1.0f);
10207 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
10211 rsurface.texture = NULL;
10214 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
10216 // R_Mesh_ResetTextureState();
10217 R_SetupShader_Generic_NoTexture(false, false);
10218 GL_DepthRange(0, 1);
10219 GL_DepthTest(!r_showdisabledepthtest.integer);
10220 GL_DepthMask(false);
10221 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10223 if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
10227 qboolean cullbox = false;
10228 const q3mbrush_t *brush;
10229 const bih_t *bih = &model->collision_bih;
10230 const bih_leaf_t *bihleaf;
10231 float vertex3f[3][3];
10232 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
10233 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
10235 if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
10237 switch (bihleaf->type)
10240 brush = model->brush.data_brushes + bihleaf->itemindex;
10241 if (brush->colbrushf && brush->colbrushf->numtriangles)
10243 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);
10244 R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
10245 R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
10248 case BIH_COLLISIONTRIANGLE:
10249 triangleindex = bihleaf->itemindex;
10250 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
10251 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
10252 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
10253 GL_Color((bihleafindex & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value);
10254 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
10255 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
10257 case BIH_RENDERTRIANGLE:
10258 triangleindex = bihleaf->itemindex;
10259 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
10260 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
10261 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[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);
10270 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
10273 if (r_showtris.value > 0 && qglPolygonMode)
10275 if (r_showdisabledepthtest.integer)
10277 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10278 GL_DepthMask(false);
10282 GL_BlendFunc(GL_ONE, GL_ZERO);
10283 GL_DepthMask(true);
10285 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
10286 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10288 if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10290 rsurface.texture = R_GetCurrentTexture(surface->texture);
10291 if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10293 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
10294 if (!rsurface.texture->currentlayers->depthmask)
10295 GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
10296 else if (ent == r_refdef.scene.worldentity)
10297 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
10299 GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
10300 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
10304 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
10305 rsurface.texture = NULL;
10309 // FIXME! implement r_shownormals with just triangles
10310 if (r_shownormals.value != 0 && qglBegin)
10314 if (r_showdisabledepthtest.integer)
10316 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10317 GL_DepthMask(false);
10321 GL_BlendFunc(GL_ONE, GL_ZERO);
10322 GL_DepthMask(true);
10324 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10326 if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10328 rsurface.texture = R_GetCurrentTexture(surface->texture);
10329 if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10331 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
10332 qglBegin(GL_LINES);
10333 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
10335 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10337 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10338 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10339 qglVertex3f(v[0], v[1], v[2]);
10340 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10341 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10342 qglVertex3f(v[0], v[1], v[2]);
10345 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
10347 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10349 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10350 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
10351 qglVertex3f(v[0], v[1], v[2]);
10352 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
10353 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10354 qglVertex3f(v[0], v[1], v[2]);
10357 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
10359 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10361 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10362 GL_Color(0, r_refdef.view.colorscale, 0, 1);
10363 qglVertex3f(v[0], v[1], v[2]);
10364 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
10365 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10366 qglVertex3f(v[0], v[1], v[2]);
10369 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
10371 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10373 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10374 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10375 qglVertex3f(v[0], v[1], v[2]);
10376 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10377 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10378 qglVertex3f(v[0], v[1], v[2]);
10385 rsurface.texture = NULL;
10391 int r_maxsurfacelist = 0;
10392 const msurface_t **r_surfacelist = NULL;
10393 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass)
10395 int i, j, endj, flagsmask;
10396 dp_model_t *model = ent->model;
10397 msurface_t *surfaces;
10398 unsigned char *update;
10399 int numsurfacelist = 0;
10403 if (r_maxsurfacelist < model->num_surfaces)
10405 r_maxsurfacelist = model->num_surfaces;
10407 Mem_Free((msurface_t **)r_surfacelist);
10408 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
10411 if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
10412 RSurf_ActiveModelEntity(ent, false, false, false);
10414 RSurf_ActiveModelEntity(ent, true, true, true);
10415 else if (depthonly)
10416 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
10418 RSurf_ActiveModelEntity(ent, true, true, false);
10420 surfaces = model->data_surfaces;
10421 update = model->brushq1.lightmapupdateflags;
10423 // update light styles
10424 if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0)
10426 model_brush_lightstyleinfo_t *style;
10427 for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
10429 if (style->value != r_refdef.scene.lightstylevalue[style->style])
10431 int *list = style->surfacelist;
10432 style->value = r_refdef.scene.lightstylevalue[style->style];
10433 for (j = 0;j < style->numsurfaces;j++)
10434 update[list[j]] = true;
10439 flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
10443 R_DrawDebugModel();
10444 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10448 rsurface.lightmaptexture = NULL;
10449 rsurface.deluxemaptexture = NULL;
10450 rsurface.uselightmaptexture = false;
10451 rsurface.texture = NULL;
10452 rsurface.rtlight = NULL;
10453 numsurfacelist = 0;
10454 // add visible surfaces to draw list
10455 if (ent == r_refdef.scene.worldentity)
10457 // for the world entity, check surfacevisible
10458 for (i = 0;i < model->nummodelsurfaces;i++)
10460 j = model->sortedmodelsurfaces[i];
10461 if (r_refdef.viewcache.world_surfacevisible[j])
10462 r_surfacelist[numsurfacelist++] = surfaces + j;
10467 // add all surfaces
10468 for (i = 0; i < model->nummodelsurfaces; i++)
10469 r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
10471 // don't do anything if there were no surfaces
10472 if (!numsurfacelist)
10474 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10477 // update lightmaps if needed
10481 for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
10486 R_BuildLightMap(ent, surfaces + j);
10491 R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass);
10493 // add to stats if desired
10494 if (r_speeds.integer && !skysurfaces && !depthonly)
10496 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10497 for (j = 0;j < numsurfacelist;j++)
10498 r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10501 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10504 void R_DebugLine(vec3_t start, vec3_t end)
10506 dp_model_t *mod = CL_Mesh_UI();
10508 int e0, e1, e2, e3;
10509 float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10510 float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10511 float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10514 // transform to screen coords first
10515 Vector4Set(w[0], start[0], start[1], start[2], 1);
10516 Vector4Set(w[1], end[0], end[1], end[2], 1);
10517 R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10518 R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10519 x1 = s[0][0] * vid_conwidth.value / vid.width;
10520 y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10521 x2 = s[1][0] * vid_conwidth.value / vid.width;
10522 y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10523 //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10525 // add the line to the UI mesh for drawing later
10527 // width is measured in real pixels
10528 if (fabs(x2 - x1) > fabs(y2 - y1))
10531 offsety = 0.5f * width * vid_conheight.value / vid.height;
10535 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10538 surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_VERTEXCOLOR), true);
10539 e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10540 e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10541 e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10542 e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10543 Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10544 Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10549 void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass)
10552 static texture_t texture;
10553 static msurface_t surface;
10554 const msurface_t *surfacelist = &surface;
10556 // fake enough texture and surface state to render this geometry
10558 texture.update_lastrenderframe = -1; // regenerate this texture
10559 texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10560 texture.basealpha = 1.0f;
10561 texture.currentskinframe = skinframe;
10562 texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10563 texture.offsetmapping = OFFSETMAPPING_OFF;
10564 texture.offsetscale = 1;
10565 texture.specularscalemod = 1;
10566 texture.specularpowermod = 1;
10567 texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10568 // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
10569 // JUST GREP FOR "specularscalemod = 1".
10571 for (q = 0; q < 3; q++)
10573 texture.render_glowmod[q] = r_refdef.view.colorscale * r_hdr_glowintensity.value;
10574 texture.render_modellight_lightdir[q] = q == 2;
10575 texture.render_modellight_ambient[q] = r_refdef.view.colorscale * r_refdef.scene.ambientintensity;
10576 texture.render_modellight_diffuse[q] = r_refdef.view.colorscale;
10577 texture.render_modellight_specular[q] = r_refdef.view.colorscale;
10578 texture.render_lightmap_ambient[q] = r_refdef.view.colorscale * r_refdef.scene.ambientintensity;
10579 texture.render_lightmap_diffuse[q] = r_refdef.view.colorscale * r_refdef.scene.lightmapintensity;
10580 texture.render_lightmap_specular[q] = r_refdef.view.colorscale;
10581 texture.render_rtlight_diffuse[q] = r_refdef.view.colorscale;
10582 texture.render_rtlight_specular[q] = r_refdef.view.colorscale;
10584 texture.currentalpha = 1.0f;
10586 surface.texture = &texture;
10587 surface.num_triangles = numtriangles;
10588 surface.num_firsttriangle = firsttriangle;
10589 surface.num_vertices = numvertices;
10590 surface.num_firstvertex = firstvertex;
10593 rsurface.texture = R_GetCurrentTexture(surface.texture);
10594 rsurface.lightmaptexture = NULL;
10595 rsurface.deluxemaptexture = NULL;
10596 rsurface.uselightmaptexture = false;
10597 R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);
10600 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)
10602 static msurface_t surface;
10603 const msurface_t *surfacelist = &surface;
10605 // fake enough texture and surface state to render this geometry
10606 surface.texture = texture;
10607 surface.num_triangles = numtriangles;
10608 surface.num_firsttriangle = firsttriangle;
10609 surface.num_vertices = numvertices;
10610 surface.num_firstvertex = firstvertex;
10613 rsurface.texture = R_GetCurrentTexture(surface.texture);
10614 rsurface.lightmaptexture = NULL;
10615 rsurface.deluxemaptexture = NULL;
10616 rsurface.uselightmaptexture = false;
10617 R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);