2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 #include "cl_collision.h"
32 // Enable NVIDIA High Performance Graphics while using Integrated Graphics.
36 __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
42 mempool_t *r_main_mempool;
43 rtexturepool_t *r_main_texturepool;
45 static int r_textureframe = 0; ///< used only by R_GetCurrentTexture
47 static qboolean r_loadnormalmap;
48 static qboolean r_loadgloss;
50 static qboolean r_loaddds;
51 static qboolean r_savedds;
52 static qboolean r_gpuskeletal;
59 cvar_t r_motionblur = {CVAR_SAVE, "r_motionblur", "0", "screen motionblur - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
60 cvar_t r_damageblur = {CVAR_SAVE, "r_damageblur", "0", "screen motionblur based on damage - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
61 cvar_t r_motionblur_averaging = {CVAR_SAVE, "r_motionblur_averaging", "0.1", "sliding average reaction time for velocity (higher = slower adaption to change)"};
62 cvar_t r_motionblur_randomize = {CVAR_SAVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"};
63 cvar_t r_motionblur_minblur = {CVAR_SAVE, "r_motionblur_minblur", "0.5", "factor of blur to apply at all times (always have this amount of blur no matter what the other factors are)"};
64 cvar_t r_motionblur_maxblur = {CVAR_SAVE, "r_motionblur_maxblur", "0.9", "maxmimum amount of blur"};
65 cvar_t r_motionblur_velocityfactor = {CVAR_SAVE, "r_motionblur_velocityfactor", "1", "factoring in of player velocity to the blur equation - the faster the player moves around the map, the more blur they get"};
66 cvar_t r_motionblur_velocityfactor_minspeed = {CVAR_SAVE, "r_motionblur_velocityfactor_minspeed", "400", "lower value of velocity when it starts to factor into blur equation"};
67 cvar_t r_motionblur_velocityfactor_maxspeed = {CVAR_SAVE, "r_motionblur_velocityfactor_maxspeed", "800", "upper value of velocity when it reaches the peak factor into blur equation"};
68 cvar_t r_motionblur_mousefactor = {CVAR_SAVE, "r_motionblur_mousefactor", "2", "factoring in of mouse acceleration to the blur equation - the faster the player turns their mouse, the more blur they get"};
69 cvar_t r_motionblur_mousefactor_minspeed = {CVAR_SAVE, "r_motionblur_mousefactor_minspeed", "0", "lower value of mouse acceleration when it starts to factor into blur equation"};
70 cvar_t r_motionblur_mousefactor_maxspeed = {CVAR_SAVE, "r_motionblur_mousefactor_maxspeed", "50", "upper value of mouse acceleration when it reaches the peak factor into blur equation"};
72 // TODO do we want a r_equalize_entities cvar that works on all ents, or would that be a cheat?
73 cvar_t r_equalize_entities_fullbright = {CVAR_SAVE, "r_equalize_entities_fullbright", "0", "render fullbright entities by equalizing their lightness, not by not rendering light (DEPRECATED)"};
74 cvar_t r_equalize_entities_minambient = {CVAR_SAVE, "r_equalize_entities_minambient", "0.5", "light equalizing: ensure at least this ambient/diffuse ratio (DEPRECATED)"};
75 cvar_t r_equalize_entities_by = {CVAR_SAVE, "r_equalize_entities_by", "0.7", "light equalizing: exponent of dynamics compression (0 = no compression, 1 = full compression) (DEPRECATED)"};
76 cvar_t r_equalize_entities_to = {CVAR_SAVE, "r_equalize_entities_to", "0.8", "light equalizing: target light level (DEPRECATED)"};
78 cvar_t r_depthfirst = {CVAR_SAVE, "r_depthfirst", "0", "renders a depth-only version of the scene before normal rendering begins to eliminate overdraw, values: 0 = off, 1 = world depth, 2 = world and model depth"};
79 cvar_t r_useinfinitefarclip = {CVAR_SAVE, "r_useinfinitefarclip", "1", "enables use of a special kind of projection matrix that has an extremely large farclip"};
80 cvar_t r_farclip_base = {0, "r_farclip_base", "65536", "farclip (furthest visible distance) for rendering when r_useinfinitefarclip is 0"};
81 cvar_t r_farclip_world = {0, "r_farclip_world", "2", "adds map size to farclip multiplied by this value"};
82 cvar_t r_nearclip = {0, "r_nearclip", "1", "distance from camera of nearclip plane" };
83 cvar_t r_deformvertexes = {0, "r_deformvertexes", "1", "allows use of deformvertexes in shader files (can be turned off to check performance impact)"};
84 cvar_t r_transparent = {0, "r_transparent", "1", "allows use of transparent surfaces (can be turned off to check performance impact)"};
85 cvar_t r_transparent_alphatocoverage = {0, "r_transparent_alphatocoverage", "1", "enables GL_ALPHA_TO_COVERAGE antialiasing technique on alphablend and alphatest surfaces when using vid_samples 2 or higher"};
86 cvar_t r_transparent_sortsurfacesbynearest = {0, "r_transparent_sortsurfacesbynearest", "1", "sort entity and world surfaces by nearest point on bounding box instead of using the center of the bounding box, usually reduces sorting artifacts"};
87 cvar_t r_transparent_useplanardistance = {0, "r_transparent_useplanardistance", "0", "sort transparent meshes by distance from view plane rather than spherical distance to the chosen point"};
88 cvar_t r_showoverdraw = {0, "r_showoverdraw", "0", "shows overlapping geometry"};
89 cvar_t r_showbboxes = {0, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%, 10 = 100%)"};
90 cvar_t r_showbboxes_client = { 0, "r_showbboxes_client", "0", "shows bounding boxes of clientside qc entities, value controls opacity scaling (1 = 10%, 10 = 100%)" };
91 cvar_t r_showsurfaces = {0, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 2 shows triangle draw order (for analyzing whether meshes are optimized for vertex cache)"};
92 cvar_t r_showtris = {0, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
93 cvar_t r_shownormals = {0, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
94 cvar_t r_showlighting = {0, "r_showlighting", "0", "shows areas lit by lights, useful for finding out why some areas of a map render slowly (bright orange = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
95 cvar_t r_showshadowvolumes = {0, "r_showshadowvolumes", "0", "shows areas shadowed by lights, useful for finding out why some areas of a map render slowly (bright blue = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
96 cvar_t r_showcollisionbrushes = {0, "r_showcollisionbrushes", "0", "draws collision brushes in quake3 maps (mode 1), mode 2 disables rendering of world (trippy!)"};
97 cvar_t r_showcollisionbrushes_polygonfactor = {0, "r_showcollisionbrushes_polygonfactor", "-1", "expands outward the brush polygons a little bit, used to make collision brushes appear infront of walls"};
98 cvar_t r_showcollisionbrushes_polygonoffset = {0, "r_showcollisionbrushes_polygonoffset", "0", "nudges brush polygon depth in hardware depth units, used to make collision brushes appear infront of walls"};
99 cvar_t r_showdisabledepthtest = {0, "r_showdisabledepthtest", "0", "disables depth testing on r_show* cvars, allowing you to see what hidden geometry the graphics card is processing"};
100 cvar_t r_showspriteedges = {0, "r_showspriteedges", "0", "renders a debug outline to show the polygon shape of each sprite frame rendered (may be 2 or more in case of interpolated animations), for debugging rendering bugs with specific view types"};
101 cvar_t r_showparticleedges = {0, "r_showparticleedges", "0", "renders a debug outline to show the polygon shape of each particle, for debugging rendering bugs with specific view types"};
102 cvar_t r_drawportals = {0, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
103 cvar_t r_drawentities = {0, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
104 cvar_t r_draw2d = {0, "r_draw2d","1", "draw 2D stuff (dangerous to turn off)"};
105 cvar_t r_drawworld = {0, "r_drawworld","1", "draw world (most static stuff)"};
106 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1", "draw your weapon model"};
107 cvar_t r_drawexteriormodel = {0, "r_drawexteriormodel","1", "draw your player model (e.g. in chase cam, reflections)"};
108 cvar_t r_cullentities_trace = {0, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
109 cvar_t r_cullentities_trace_entityocclusion = { 0, "r_cullentities_trace_entityocclusion", "1", "check for occluding entities such as doors, not just world hull" };
110 cvar_t r_cullentities_trace_samples = {0, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling (in addition to center sample)"};
111 cvar_t r_cullentities_trace_tempentitysamples = {0, "r_cullentities_trace_tempentitysamples", "-1", "number of samples to test for entity culling of temp entities (including all CSQC entities), -1 disables trace culling on these entities to prevent flicker (pvs still applies)"};
112 cvar_t r_cullentities_trace_enlarge = {0, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
113 cvar_t r_cullentities_trace_expand = {0, "r_cullentities_trace_expand", "0", "box expanded by this many units for entity culling"};
114 cvar_t r_cullentities_trace_pad = {0, "r_cullentities_trace_pad", "8", "accept traces that hit within this many units of the box"};
115 cvar_t r_cullentities_trace_delay = {0, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
116 cvar_t r_cullentities_trace_eyejitter = {0, "r_cullentities_trace_eyejitter", "16", "randomly offset rays from the eye by this much to reduce the odds of flickering"};
117 cvar_t r_sortentities = {0, "r_sortentities", "0", "sort entities before drawing (might be faster)"};
118 cvar_t r_speeds = {0, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
119 cvar_t r_fullbright = {0, "r_fullbright","0", "makes map very bright and renders faster"};
121 cvar_t r_fakelight = {0, "r_fakelight","0", "render 'fake' lighting instead of real lightmaps (DEPRECATED)"};
122 cvar_t r_fakelight_intensity = {0, "r_fakelight_intensity","0.75", "fakelight intensity modifier (DEPRECATED)"};
123 #define FAKELIGHT_ENABLED (r_fakelight.integer >= 2 || (r_fakelight.integer && r_refdef.scene.worldmodel && !r_refdef.scene.worldmodel->lit))
125 cvar_t r_fullbright_directed = {0, "r_fullbright_directed", "0", "render fullbright things (unlit worldmodel and EF_FULLBRIGHT entities, but not fullbright shaders) using a constant light direction instead to add more depth while keeping uniform brightness"};
126 cvar_t r_fullbright_directed_ambient = {0, "r_fullbright_directed_ambient", "0.5", "ambient light multiplier for directed fullbright"};
127 cvar_t r_fullbright_directed_diffuse = {0, "r_fullbright_directed_diffuse", "0.75", "diffuse light multiplier for directed fullbright"};
128 cvar_t r_fullbright_directed_pitch = {0, "r_fullbright_directed_pitch", "20", "constant pitch direction ('height') of the fake light source to use for fullbright"};
129 cvar_t r_fullbright_directed_pitch_relative = {0, "r_fullbright_directed_pitch_relative", "0", "whether r_fullbright_directed_pitch is interpreted as absolute (0) or relative (1) pitch"};
131 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1", "opacity of water polygons"};
132 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
133 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
134 cvar_t r_shadows = {CVAR_SAVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this); when set to 2, always cast the shadows in the direction set by r_shadows_throwdirection, otherwise use the model lighting."};
135 cvar_t r_shadows_darken = {CVAR_SAVE, "r_shadows_darken", "0.5", "how much shadowed areas will be darkened"};
136 cvar_t r_shadows_throwdistance = {CVAR_SAVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
137 cvar_t r_shadows_throwdirection = {CVAR_SAVE, "r_shadows_throwdirection", "0 0 -1", "override throwing direction for r_shadows 2"};
138 cvar_t r_shadows_drawafterrtlighting = {CVAR_SAVE, "r_shadows_drawafterrtlighting", "0", "draw fake shadows AFTER realtime lightning is drawn. May be useful for simulating fast sunlight on large outdoor maps with only one noshadow rtlight. The price is less realistic appearance of dynamic light shadows."};
139 cvar_t r_shadows_castfrombmodels = {CVAR_SAVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
140 cvar_t r_shadows_focus = {CVAR_SAVE, "r_shadows_focus", "0 0 0", "offset the shadowed area focus"};
141 cvar_t r_shadows_shadowmapscale = {CVAR_SAVE, "r_shadows_shadowmapscale", "0.25", "higher values increase shadowmap quality at a cost of area covered (multiply global shadowmap precision) for fake shadows. Needs shadowmapping ON."};
142 cvar_t r_shadows_shadowmapbias = {CVAR_SAVE, "r_shadows_shadowmapbias", "-1", "sets shadowmap bias for fake shadows. -1 sets the value of r_shadow_shadowmapping_bias. Needs shadowmapping ON."};
143 cvar_t r_q1bsp_skymasking = {0, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
144 cvar_t r_polygonoffset_submodel_factor = {0, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
145 cvar_t r_polygonoffset_submodel_offset = {0, "r_polygonoffset_submodel_offset", "14", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
146 cvar_t r_polygonoffset_decals_factor = {0, "r_polygonoffset_decals_factor", "0", "biases depth values of decals to prevent z-fighting artifacts"};
147 cvar_t r_polygonoffset_decals_offset = {0, "r_polygonoffset_decals_offset", "-14", "biases depth values of decals to prevent z-fighting artifacts"};
148 cvar_t r_fog_exp2 = {0, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"};
149 cvar_t r_fog_clear = {0, "r_fog_clear", "1", "clears renderbuffer with fog color before render starts"};
150 cvar_t r_drawfog = {CVAR_SAVE, "r_drawfog", "1", "allows one to disable fog rendering"};
151 cvar_t r_transparentdepthmasking = {CVAR_SAVE, "r_transparentdepthmasking", "0", "enables depth writes on transparent meshes whose materially is normally opaque, this prevents seeing the inside of a transparent mesh"};
152 cvar_t r_transparent_sortmindist = {CVAR_SAVE, "r_transparent_sortmindist", "0", "lower distance limit for transparent sorting"};
153 cvar_t r_transparent_sortmaxdist = {CVAR_SAVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"};
154 cvar_t r_transparent_sortarraysize = {CVAR_SAVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"};
155 cvar_t r_celshading = {CVAR_SAVE, "r_celshading", "0", "cartoon-style light shading (OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9
156 cvar_t r_celoutlines = {CVAR_SAVE, "r_celoutlines", "0", "cartoon-style outlines (requires r_shadow_deferred; OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9
158 cvar_t gl_fogenable = {0, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
159 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
160 cvar_t gl_fogred = {0, "gl_fogred","0.3", "nehahra fog color red value (for Nehahra compatibility only)"};
161 cvar_t gl_foggreen = {0, "gl_foggreen","0.3", "nehahra fog color green value (for Nehahra compatibility only)"};
162 cvar_t gl_fogblue = {0, "gl_fogblue","0.3", "nehahra fog color blue value (for Nehahra compatibility only)"};
163 cvar_t gl_fogstart = {0, "gl_fogstart", "0", "nehahra fog start distance (for Nehahra compatibility only)"};
164 cvar_t gl_fogend = {0, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
165 cvar_t gl_skyclip = {0, "gl_skyclip", "4608", "nehahra farclip distance - the real fog end (for Nehahra compatibility only)"};
167 cvar_t r_texture_dds_load = {CVAR_SAVE, "r_texture_dds_load", "0", "load compressed dds/filename.dds texture instead of filename.tga, if the file exists (requires driver support)"};
168 cvar_t r_texture_dds_save = {CVAR_SAVE, "r_texture_dds_save", "0", "save compressed dds/filename.dds texture when filename.tga is loaded, so that it can be loaded instead next time"};
170 cvar_t r_textureunits = {0, "r_textureunits", "32", "number of texture units to use in GL 1.1 and GL 1.3 rendering paths"};
171 static cvar_t gl_combine = {CVAR_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"};
172 static cvar_t r_glsl = {CVAR_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"};
174 cvar_t r_usedepthtextures = {CVAR_SAVE, "r_usedepthtextures", "1", "use depth texture instead of depth renderbuffer where possible, uses less video memory but may render slower (or faster) depending on hardware"};
175 cvar_t r_viewfbo = {CVAR_SAVE, "r_viewfbo", "0", "enables use of an 8bit (1) or 16bit (2) or 32bit (3) per component float framebuffer render, which may be at a different resolution than the video mode"};
176 cvar_t r_rendertarget_debug = {0, "r_rendertarget_debug", "-1", "replaces the view with the contents of the specified render target (by number - note that these can fluctuate depending on scene)"};
177 cvar_t r_viewscale = {CVAR_SAVE, "r_viewscale", "1", "scaling factor for resolution of the fbo rendering method, must be > 0, can be above 1 for a costly antialiasing behavior, typical values are 0.5 for 1/4th as many pixels rendered, or 1 for normal rendering"};
178 cvar_t r_viewscale_fpsscaling = {CVAR_SAVE, "r_viewscale_fpsscaling", "0", "change resolution based on framerate"};
179 cvar_t r_viewscale_fpsscaling_min = {CVAR_SAVE, "r_viewscale_fpsscaling_min", "0.0625", "worst acceptable quality"};
180 cvar_t r_viewscale_fpsscaling_multiply = {CVAR_SAVE, "r_viewscale_fpsscaling_multiply", "5", "adjust quality up or down by the frametime difference from 1.0/target, multiplied by this factor"};
181 cvar_t r_viewscale_fpsscaling_stepsize = {CVAR_SAVE, "r_viewscale_fpsscaling_stepsize", "0.01", "smallest adjustment to hit the target framerate (this value prevents minute oscillations)"};
182 cvar_t r_viewscale_fpsscaling_stepmax = {CVAR_SAVE, "r_viewscale_fpsscaling_stepmax", "1.00", "largest adjustment to hit the target framerate (this value prevents wild overshooting of the estimate)"};
183 cvar_t r_viewscale_fpsscaling_target = {CVAR_SAVE, "r_viewscale_fpsscaling_target", "70", "desired framerate"};
185 cvar_t r_glsl_skeletal = {CVAR_SAVE, "r_glsl_skeletal", "1", "render skeletal models faster using a gpu-skinning technique"};
186 cvar_t r_glsl_deluxemapping = {CVAR_SAVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
187 cvar_t r_glsl_offsetmapping = {CVAR_SAVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
188 cvar_t r_glsl_offsetmapping_steps = {CVAR_SAVE, "r_glsl_offsetmapping_steps", "2", "offset mapping steps (note: too high values may be not supported by your GPU)"};
189 cvar_t r_glsl_offsetmapping_reliefmapping = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
190 cvar_t r_glsl_offsetmapping_reliefmapping_steps = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_steps", "10", "relief mapping steps (note: too high values may be not supported by your GPU)"};
191 cvar_t r_glsl_offsetmapping_reliefmapping_refinesteps = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_refinesteps", "5", "relief mapping refine steps (these are a binary search executed as the last step as given by r_glsl_offsetmapping_reliefmapping_steps)"};
192 cvar_t r_glsl_offsetmapping_scale = {CVAR_SAVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
193 cvar_t r_glsl_offsetmapping_lod = {CVAR_SAVE, "r_glsl_offsetmapping_lod", "0", "apply distance-based level-of-detail correction to number of offsetmappig steps, effectively making it render faster on large open-area maps"};
194 cvar_t r_glsl_offsetmapping_lod_distance = {CVAR_SAVE, "r_glsl_offsetmapping_lod_distance", "32", "first LOD level distance, second level (-50% steps) is 2x of this, third (33%) - 3x etc."};
195 cvar_t r_glsl_postprocess = {CVAR_SAVE, "r_glsl_postprocess", "0", "use a GLSL postprocessing shader"};
196 cvar_t r_glsl_postprocess_uservec1 = {CVAR_SAVE, "r_glsl_postprocess_uservec1", "0 0 0 0", "a 4-component vector to pass as uservec1 to the postprocessing shader (only useful if default.glsl has been customized)"};
197 cvar_t r_glsl_postprocess_uservec2 = {CVAR_SAVE, "r_glsl_postprocess_uservec2", "0 0 0 0", "a 4-component vector to pass as uservec2 to the postprocessing shader (only useful if default.glsl has been customized)"};
198 cvar_t r_glsl_postprocess_uservec3 = {CVAR_SAVE, "r_glsl_postprocess_uservec3", "0 0 0 0", "a 4-component vector to pass as uservec3 to the postprocessing shader (only useful if default.glsl has been customized)"};
199 cvar_t r_glsl_postprocess_uservec4 = {CVAR_SAVE, "r_glsl_postprocess_uservec4", "0 0 0 0", "a 4-component vector to pass as uservec4 to the postprocessing shader (only useful if default.glsl has been customized)"};
200 cvar_t r_glsl_postprocess_uservec1_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec1_enable", "1", "enables postprocessing uservec1 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
201 cvar_t r_glsl_postprocess_uservec2_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec2_enable", "1", "enables postprocessing uservec2 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
202 cvar_t r_glsl_postprocess_uservec3_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec3_enable", "1", "enables postprocessing uservec3 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
203 cvar_t r_glsl_postprocess_uservec4_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec4_enable", "1", "enables postprocessing uservec4 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
205 cvar_t r_water = {CVAR_SAVE, "r_water", "0", "whether to use reflections and refraction on water surfaces (note: r_wateralpha must be set below 1)"};
206 cvar_t r_water_cameraentitiesonly = {CVAR_SAVE, "r_water_cameraentitiesonly", "0", "whether to only show QC-defined reflections/refractions (typically used for camera- or portal-like effects)"};
207 cvar_t r_water_clippingplanebias = {CVAR_SAVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
208 cvar_t r_water_resolutionmultiplier = {CVAR_SAVE, "r_water_resolutionmultiplier", "0.5", "multiplier for screen resolution when rendering refracted/reflected scenes, 1 is full quality, lower values are faster"};
209 cvar_t r_water_refractdistort = {CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
210 cvar_t r_water_reflectdistort = {CVAR_SAVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
211 cvar_t r_water_scissormode = {0, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
212 cvar_t r_water_lowquality = {0, "r_water_lowquality", "0", "special option to accelerate water rendering, 1 disables shadows and particles, 2 disables all dynamic lights"};
213 cvar_t r_water_hideplayer = {CVAR_SAVE, "r_water_hideplayer", "0", "if set to 1 then player will be hidden in refraction views, if set to 2 then player will also be hidden in reflection views, player is always visible in camera views"};
215 cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"};
216 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
217 cvar_t r_lerplightstyles = {CVAR_SAVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
218 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
220 cvar_t r_bloom = {CVAR_SAVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
221 cvar_t r_bloom_colorscale = {CVAR_SAVE, "r_bloom_colorscale", "1", "how bright the glow is"};
223 cvar_t r_bloom_brighten = {CVAR_SAVE, "r_bloom_brighten", "2", "how bright the glow is, after subtract/power"};
224 cvar_t r_bloom_blur = {CVAR_SAVE, "r_bloom_blur", "4", "how large the glow is"};
225 cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
226 cvar_t r_bloom_colorexponent = {CVAR_SAVE, "r_bloom_colorexponent", "1", "how exaggerated the glow is"};
227 cvar_t r_bloom_colorsubtract = {CVAR_SAVE, "r_bloom_colorsubtract", "0.125", "reduces bloom colors by a certain amount"};
228 cvar_t r_bloom_scenebrightness = {CVAR_SAVE, "r_bloom_scenebrightness", "1", "global rendering brightness when bloom is enabled"};
230 cvar_t r_hdr_scenebrightness = {CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
231 cvar_t r_hdr_glowintensity = {CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
232 cvar_t r_hdr_irisadaptation = {CVAR_SAVE, "r_hdr_irisadaptation", "0", "adjust scene brightness according to light intensity at player location"};
233 cvar_t r_hdr_irisadaptation_multiplier = {CVAR_SAVE, "r_hdr_irisadaptation_multiplier", "2", "brightness at which value will be 1.0"};
234 cvar_t r_hdr_irisadaptation_minvalue = {CVAR_SAVE, "r_hdr_irisadaptation_minvalue", "0.5", "minimum value that can result from multiplier / brightness"};
235 cvar_t r_hdr_irisadaptation_maxvalue = {CVAR_SAVE, "r_hdr_irisadaptation_maxvalue", "4", "maximum value that can result from multiplier / brightness"};
236 cvar_t r_hdr_irisadaptation_value = {0, "r_hdr_irisadaptation_value", "1", "current value as scenebrightness multiplier, changes continuously when irisadaptation is active"};
237 cvar_t r_hdr_irisadaptation_fade_up = {CVAR_SAVE, "r_hdr_irisadaptation_fade_up", "0.1", "fade rate at which value adjusts to darkness"};
238 cvar_t r_hdr_irisadaptation_fade_down = {CVAR_SAVE, "r_hdr_irisadaptation_fade_down", "0.5", "fade rate at which value adjusts to brightness"};
239 cvar_t r_hdr_irisadaptation_radius = {CVAR_SAVE, "r_hdr_irisadaptation_radius", "15", "lighting within this many units of the eye is averaged"};
241 cvar_t r_smoothnormals_areaweighting = {0, "r_smoothnormals_areaweighting", "1", "uses significantly faster (and supposedly higher quality) area-weighted vertex normals and tangent vectors rather than summing normalized triangle normals and tangents"};
243 cvar_t developer_texturelogging = {0, "developer_texturelogging", "0", "produces a textures.log file containing names of skins and map textures the engine tried to load"};
245 cvar_t gl_lightmaps = {0, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers), a value of 2 keeps normalmap shading"};
247 cvar_t r_test = {0, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
249 cvar_t r_batch_multidraw = {CVAR_SAVE, "r_batch_multidraw", "1", "issue multiple glDrawElements calls when rendering a batch of surfaces with the same texture (otherwise the index data is copied to make it one draw)"};
250 cvar_t r_batch_multidraw_mintriangles = {CVAR_SAVE, "r_batch_multidraw_mintriangles", "0", "minimum number of triangles to activate multidraw path (copying small groups of triangles may be faster)"};
251 cvar_t r_batch_debugdynamicvertexpath = {CVAR_SAVE, "r_batch_debugdynamicvertexpath", "0", "force the dynamic batching code path for debugging purposes"};
252 cvar_t r_batch_dynamicbuffer = {CVAR_SAVE, "r_batch_dynamicbuffer", "0", "use vertex/index buffers for drawing dynamic and copytriangles batches"};
254 cvar_t r_glsl_saturation = {CVAR_SAVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
255 cvar_t r_glsl_saturation_redcompensate = {CVAR_SAVE, "r_glsl_saturation_redcompensate", "0", "a 'vampire sight' addition to desaturation effect, does compensation for red color, r_glsl_restart is required"};
257 cvar_t r_glsl_vertextextureblend_usebothalphas = {CVAR_SAVE, "r_glsl_vertextextureblend_usebothalphas", "0", "use both alpha layers on vertex blended surfaces, each alpha layer sets amount of 'blend leak' on another layer, requires mod_q3shader_force_terrain_alphaflag on."};
259 cvar_t r_framedatasize = {CVAR_SAVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"};
260 cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
262 {CVAR_SAVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"},
263 {CVAR_SAVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"},
264 {CVAR_SAVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"},
265 {CVAR_SAVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
268 extern cvar_t v_glslgamma_2d;
270 extern qboolean v_flipped_state;
272 r_framebufferstate_t r_fb;
274 /// shadow volume bsp struct with automatically growing nodes buffer
277 int r_uniformbufferalignment = 32; // dynamically updated to match GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
279 rtexture_t *r_texture_blanknormalmap;
280 rtexture_t *r_texture_white;
281 rtexture_t *r_texture_grey128;
282 rtexture_t *r_texture_black;
283 rtexture_t *r_texture_notexture;
284 rtexture_t *r_texture_whitecube;
285 rtexture_t *r_texture_normalizationcube;
286 rtexture_t *r_texture_fogattenuation;
287 rtexture_t *r_texture_fogheighttexture;
288 rtexture_t *r_texture_gammaramps;
289 unsigned int r_texture_gammaramps_serial;
290 //rtexture_t *r_texture_fogintensity;
291 rtexture_t *r_texture_reflectcube;
293 // TODO: hash lookups?
294 typedef struct cubemapinfo_s
301 int r_texture_numcubemaps;
302 cubemapinfo_t *r_texture_cubemaps[MAX_CUBEMAPS];
304 unsigned int r_queries[MAX_OCCLUSION_QUERIES];
305 unsigned int r_numqueries;
306 unsigned int r_maxqueries;
308 typedef struct r_qwskincache_s
310 char name[MAX_QPATH];
311 skinframe_t *skinframe;
315 static r_qwskincache_t *r_qwskincache;
316 static int r_qwskincache_size;
318 /// vertex coordinates for a quad that covers the screen exactly
319 extern const float r_screenvertex3f[12];
320 const float r_screenvertex3f[12] =
328 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
331 for (i = 0;i < verts;i++)
342 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
345 for (i = 0;i < verts;i++)
355 // FIXME: move this to client?
358 if (gamemode == GAME_NEHAHRA)
360 Cvar_Set("gl_fogenable", "0");
361 Cvar_Set("gl_fogdensity", "0.2");
362 Cvar_Set("gl_fogred", "0.3");
363 Cvar_Set("gl_foggreen", "0.3");
364 Cvar_Set("gl_fogblue", "0.3");
366 r_refdef.fog_density = 0;
367 r_refdef.fog_red = 0;
368 r_refdef.fog_green = 0;
369 r_refdef.fog_blue = 0;
370 r_refdef.fog_alpha = 1;
371 r_refdef.fog_start = 0;
372 r_refdef.fog_end = 16384;
373 r_refdef.fog_height = 1<<30;
374 r_refdef.fog_fadedepth = 128;
375 memset(r_refdef.fog_height_texturename, 0, sizeof(r_refdef.fog_height_texturename));
378 static void R_BuildBlankTextures(void)
380 unsigned char data[4];
381 data[2] = 128; // normal X
382 data[1] = 128; // normal Y
383 data[0] = 255; // normal Z
384 data[3] = 255; // height
385 r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
390 r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
395 r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
400 r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
403 static void R_BuildNoTexture(void)
406 unsigned char pix[16][16][4];
407 // this makes a light grey/dark grey checkerboard texture
408 for (y = 0;y < 16;y++)
410 for (x = 0;x < 16;x++)
412 if ((y < 8) ^ (x < 8))
428 r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, -1, NULL);
431 static void R_BuildWhiteCube(void)
433 unsigned char data[6*1*1*4];
434 memset(data, 255, sizeof(data));
435 r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
438 static void R_BuildNormalizationCube(void)
442 vec_t s, t, intensity;
445 data = (unsigned char *)Mem_Alloc(tempmempool, 6*NORMSIZE*NORMSIZE*4);
446 for (side = 0;side < 6;side++)
448 for (y = 0;y < NORMSIZE;y++)
450 for (x = 0;x < NORMSIZE;x++)
452 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
453 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
488 intensity = 127.0f / sqrt(DotProduct(v, v));
489 data[((side*64+y)*64+x)*4+2] = (unsigned char)(128.0f + intensity * v[0]);
490 data[((side*64+y)*64+x)*4+1] = (unsigned char)(128.0f + intensity * v[1]);
491 data[((side*64+y)*64+x)*4+0] = (unsigned char)(128.0f + intensity * v[2]);
492 data[((side*64+y)*64+x)*4+3] = 255;
496 r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
500 static void R_BuildFogTexture(void)
504 unsigned char data1[FOGWIDTH][4];
505 //unsigned char data2[FOGWIDTH][4];
508 r_refdef.fogmasktable_start = r_refdef.fog_start;
509 r_refdef.fogmasktable_alpha = r_refdef.fog_alpha;
510 r_refdef.fogmasktable_range = r_refdef.fogrange;
511 r_refdef.fogmasktable_density = r_refdef.fog_density;
513 r = r_refdef.fogmasktable_range / FOGMASKTABLEWIDTH;
514 for (x = 0;x < FOGMASKTABLEWIDTH;x++)
516 d = (x * r - r_refdef.fogmasktable_start);
517 if(developer_extra.integer)
518 Con_DPrintf("%f ", d);
520 if (r_fog_exp2.integer)
521 alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d);
523 alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d);
524 if(developer_extra.integer)
525 Con_DPrintf(" : %f ", alpha);
526 alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha;
527 if(developer_extra.integer)
528 Con_DPrintf(" = %f\n", alpha);
529 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
532 for (x = 0;x < FOGWIDTH;x++)
534 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
539 //data2[x][0] = 255 - b;
540 //data2[x][1] = 255 - b;
541 //data2[x][2] = 255 - b;
544 if (r_texture_fogattenuation)
546 R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
547 //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
551 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
552 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
556 static void R_BuildFogHeightTexture(void)
558 unsigned char *inpixels;
566 strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename));
567 if (r_refdef.fogheighttexturename[0])
568 inpixels = loadimagepixelsbgra(r_refdef.fogheighttexturename, true, false, false, NULL);
571 r_refdef.fog_height_tablesize = 0;
572 if (r_texture_fogheighttexture)
573 R_FreeTexture(r_texture_fogheighttexture);
574 r_texture_fogheighttexture = NULL;
575 if (r_refdef.fog_height_table2d)
576 Mem_Free(r_refdef.fog_height_table2d);
577 r_refdef.fog_height_table2d = NULL;
578 if (r_refdef.fog_height_table1d)
579 Mem_Free(r_refdef.fog_height_table1d);
580 r_refdef.fog_height_table1d = NULL;
584 r_refdef.fog_height_tablesize = size;
585 r_refdef.fog_height_table1d = (unsigned char *)Mem_Alloc(r_main_mempool, size * 4);
586 r_refdef.fog_height_table2d = (unsigned char *)Mem_Alloc(r_main_mempool, size * size * 4);
587 memcpy(r_refdef.fog_height_table1d, inpixels, size * 4);
589 // LordHavoc: now the magic - what is that table2d for? it is a cooked
590 // average fog color table accounting for every fog layer between a point
591 // and the camera. (Note: attenuation is handled separately!)
592 for (y = 0;y < size;y++)
594 for (x = 0;x < size;x++)
600 for (j = x;j <= y;j++)
602 Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
608 for (j = x;j >= y;j--)
610 Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
615 r_refdef.fog_height_table2d[(y*size+x)*4+0] = (unsigned char)(c[0] * f);
616 r_refdef.fog_height_table2d[(y*size+x)*4+1] = (unsigned char)(c[1] * f);
617 r_refdef.fog_height_table2d[(y*size+x)*4+2] = (unsigned char)(c[2] * f);
618 r_refdef.fog_height_table2d[(y*size+x)*4+3] = (unsigned char)(c[3] * f);
621 r_texture_fogheighttexture = R_LoadTexture2D(r_main_texturepool, "fogheighttable", size, size, r_refdef.fog_height_table2d, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_CLAMP, -1, NULL);
624 //=======================================================================================================================================================
626 static const char *builtinshaderstrings[] =
628 #include "shader_glsl.h"
632 //=======================================================================================================================================================
634 typedef struct shaderpermutationinfo_s
639 shaderpermutationinfo_t;
641 typedef struct shadermodeinfo_s
643 const char *sourcebasename;
644 const char *extension;
645 const char **builtinshaderstrings;
654 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
655 shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
657 {"#define USEDIFFUSE\n", " diffuse"},
658 {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
659 {"#define USEVIEWTINT\n", " viewtint"},
660 {"#define USECOLORMAPPING\n", " colormapping"},
661 {"#define USESATURATION\n", " saturation"},
662 {"#define USEFOGINSIDE\n", " foginside"},
663 {"#define USEFOGOUTSIDE\n", " fogoutside"},
664 {"#define USEFOGHEIGHTTEXTURE\n", " fogheighttexture"},
665 {"#define USEFOGALPHAHACK\n", " fogalphahack"},
666 {"#define USEGAMMARAMPS\n", " gammaramps"},
667 {"#define USECUBEFILTER\n", " cubefilter"},
668 {"#define USEGLOW\n", " glow"},
669 {"#define USEBLOOM\n", " bloom"},
670 {"#define USESPECULAR\n", " specular"},
671 {"#define USEPOSTPROCESSING\n", " postprocessing"},
672 {"#define USEREFLECTION\n", " reflection"},
673 {"#define USEOFFSETMAPPING\n", " offsetmapping"},
674 {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
675 {"#define USESHADOWMAP2D\n", " shadowmap2d"},
676 {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm
677 {"#define USESHADOWMAPORTHO\n", " shadowmaportho"},
678 {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
679 {"#define USEALPHAKILL\n", " alphakill"},
680 {"#define USEREFLECTCUBE\n", " reflectcube"},
681 {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"},
682 {"#define USEBOUNCEGRID\n", " bouncegrid"},
683 {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm
684 {"#define USETRIPPY\n", " trippy"},
685 {"#define USEDEPTHRGB\n", " depthrgb"},
686 {"#define USEALPHAGENVERTEX\n", " alphagenvertex"},
687 {"#define USESKELETAL\n", " skeletal"},
688 {"#define USEOCCLUDE\n", " occlude"}
691 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
692 shadermodeinfo_t shadermodeinfo[SHADERLANGUAGE_COUNT][SHADERMODE_COUNT] =
694 // SHADERLANGUAGE_GLSL
696 {"combined", "glsl", builtinshaderstrings, "#define MODE_GENERIC\n", " generic"},
697 {"combined", "glsl", builtinshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
698 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
699 {"combined", "glsl", builtinshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
700 {"combined", "glsl", builtinshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
701 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
702 {"combined", "glsl", builtinshaderstrings, "#define MODE_FAKELIGHT\n", " fakelight"},
703 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
704 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
705 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
706 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
707 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
708 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
709 {"combined", "glsl", builtinshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
710 {"combined", "glsl", builtinshaderstrings, "#define MODE_WATER\n", " water"},
711 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
712 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
716 struct r_glsl_permutation_s;
717 typedef struct r_glsl_permutation_s
720 struct r_glsl_permutation_s *hashnext;
722 dpuint64 permutation;
724 /// indicates if we have tried compiling this permutation already
726 /// 0 if compilation failed
728 // texture units assigned to each detected uniform
729 int tex_Texture_First;
730 int tex_Texture_Second;
731 int tex_Texture_GammaRamps;
732 int tex_Texture_Normal;
733 int tex_Texture_Color;
734 int tex_Texture_Gloss;
735 int tex_Texture_Glow;
736 int tex_Texture_SecondaryNormal;
737 int tex_Texture_SecondaryColor;
738 int tex_Texture_SecondaryGloss;
739 int tex_Texture_SecondaryGlow;
740 int tex_Texture_Pants;
741 int tex_Texture_Shirt;
742 int tex_Texture_FogHeightTexture;
743 int tex_Texture_FogMask;
744 int tex_Texture_Lightmap;
745 int tex_Texture_Deluxemap;
746 int tex_Texture_Attenuation;
747 int tex_Texture_Cube;
748 int tex_Texture_Refraction;
749 int tex_Texture_Reflection;
750 int tex_Texture_ShadowMap2D;
751 int tex_Texture_CubeProjection;
752 int tex_Texture_ScreenNormalMap;
753 int tex_Texture_ScreenDiffuse;
754 int tex_Texture_ScreenSpecular;
755 int tex_Texture_ReflectMask;
756 int tex_Texture_ReflectCube;
757 int tex_Texture_BounceGrid;
758 /// locations of detected uniforms in program object, or -1 if not found
759 int loc_Texture_First;
760 int loc_Texture_Second;
761 int loc_Texture_GammaRamps;
762 int loc_Texture_Normal;
763 int loc_Texture_Color;
764 int loc_Texture_Gloss;
765 int loc_Texture_Glow;
766 int loc_Texture_SecondaryNormal;
767 int loc_Texture_SecondaryColor;
768 int loc_Texture_SecondaryGloss;
769 int loc_Texture_SecondaryGlow;
770 int loc_Texture_Pants;
771 int loc_Texture_Shirt;
772 int loc_Texture_FogHeightTexture;
773 int loc_Texture_FogMask;
774 int loc_Texture_Lightmap;
775 int loc_Texture_Deluxemap;
776 int loc_Texture_Attenuation;
777 int loc_Texture_Cube;
778 int loc_Texture_Refraction;
779 int loc_Texture_Reflection;
780 int loc_Texture_ShadowMap2D;
781 int loc_Texture_CubeProjection;
782 int loc_Texture_ScreenNormalMap;
783 int loc_Texture_ScreenDiffuse;
784 int loc_Texture_ScreenSpecular;
785 int loc_Texture_ReflectMask;
786 int loc_Texture_ReflectCube;
787 int loc_Texture_BounceGrid;
789 int loc_BloomBlur_Parameters;
791 int loc_Color_Ambient;
792 int loc_Color_Diffuse;
793 int loc_Color_Specular;
797 int loc_DeferredColor_Ambient;
798 int loc_DeferredColor_Diffuse;
799 int loc_DeferredColor_Specular;
800 int loc_DeferredMod_Diffuse;
801 int loc_DeferredMod_Specular;
802 int loc_DistortScaleRefractReflect;
805 int loc_FogHeightFade;
807 int loc_FogPlaneViewDist;
808 int loc_FogRangeRecip;
811 int loc_LightPosition;
812 int loc_OffsetMapping_ScaleSteps;
813 int loc_OffsetMapping_LodDistance;
814 int loc_OffsetMapping_Bias;
816 int loc_ReflectColor;
817 int loc_ReflectFactor;
818 int loc_ReflectOffset;
819 int loc_RefractColor;
821 int loc_ScreenCenterRefractReflect;
822 int loc_ScreenScaleRefractReflect;
823 int loc_ScreenToDepth;
824 int loc_ShadowMap_Parameters;
825 int loc_ShadowMap_TextureScale;
826 int loc_SpecularPower;
827 int loc_Skeletal_Transform12;
832 int loc_ViewTintColor;
834 int loc_ModelToLight;
836 int loc_BackgroundTexMatrix;
837 int loc_ModelViewProjectionMatrix;
838 int loc_ModelViewMatrix;
839 int loc_PixelToScreenTexCoord;
840 int loc_ModelToReflectCube;
841 int loc_ShadowMapMatrix;
842 int loc_BloomColorSubtract;
843 int loc_NormalmapScrollBlend;
844 int loc_BounceGridMatrix;
845 int loc_BounceGridIntensity;
846 /// uniform block bindings
847 int ubibind_Skeletal_Transform12_UniformBlock;
848 /// uniform block indices
849 int ubiloc_Skeletal_Transform12_UniformBlock;
851 r_glsl_permutation_t;
853 #define SHADERPERMUTATION_HASHSIZE 256
856 // non-degradable "lightweight" shader parameters to keep the permutations simpler
857 // these can NOT degrade! only use for simple stuff
860 SHADERSTATICPARM_SATURATION_REDCOMPENSATE = 0, ///< red compensation filter for saturation
861 SHADERSTATICPARM_EXACTSPECULARMATH = 1, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
862 SHADERSTATICPARM_POSTPROCESS_USERVEC1 = 2, ///< postprocess uservec1 is enabled
863 SHADERSTATICPARM_POSTPROCESS_USERVEC2 = 3, ///< postprocess uservec2 is enabled
864 SHADERSTATICPARM_POSTPROCESS_USERVEC3 = 4, ///< postprocess uservec3 is enabled
865 SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5, ///< postprocess uservec4 is enabled
866 SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending
867 SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7, ///< LOD for offsetmapping
868 SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1
869 SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2
870 SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
871 SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
872 SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
873 SHADERSTATICPARM_FXAA = 13 ///< fast approximate anti aliasing
875 #define SHADERSTATICPARMS_COUNT 14
877 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
878 static int shaderstaticparms_count = 0;
880 static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0};
881 #define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F))
883 extern qboolean r_shadow_shadowmapsampler;
884 extern int r_shadow_shadowmappcf;
885 qboolean R_CompileShader_CheckStaticParms(void)
887 static int r_compileshader_staticparms_save[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5];
888 memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
889 memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
892 if (r_glsl_saturation_redcompensate.integer)
893 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SATURATION_REDCOMPENSATE);
894 if (r_glsl_vertextextureblend_usebothalphas.integer)
895 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS);
896 if (r_shadow_glossexact.integer)
897 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_EXACTSPECULARMATH);
898 if (r_glsl_postprocess.integer)
900 if (r_glsl_postprocess_uservec1_enable.integer)
901 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC1);
902 if (r_glsl_postprocess_uservec2_enable.integer)
903 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC2);
904 if (r_glsl_postprocess_uservec3_enable.integer)
905 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC3);
906 if (r_glsl_postprocess_uservec4_enable.integer)
907 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
910 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_FXAA);
911 if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
912 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
914 if (r_shadow_shadowmapsampler)
915 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER);
916 if (r_shadow_shadowmappcf > 1)
917 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2);
918 else if (r_shadow_shadowmappcf)
919 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1);
920 if (r_celshading.integer)
921 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING);
922 if (r_celoutlines.integer)
923 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES);
925 return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
928 #define R_COMPILESHADER_STATICPARM_EMIT(p, n) \
929 if(r_compileshader_staticparms[(p) >> 5] & (1 << ((p) & 0x1F))) \
930 shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \
932 shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n"
933 static void R_CompileShader_AddStaticParms(unsigned int mode, dpuint64 permutation)
935 shaderstaticparms_count = 0;
938 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SATURATION_REDCOMPENSATE, "SATURATION_REDCOMPENSATE");
939 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_EXACTSPECULARMATH, "USEEXACTSPECULARMATH");
940 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC1, "USERVEC1");
941 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC2, "USERVEC2");
942 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC3, "USERVEC3");
943 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4");
944 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS");
945 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD");
946 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1");
947 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2");
948 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
949 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
950 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
951 R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
954 /// information about each possible shader permutation
955 r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
956 /// currently selected permutation
957 r_glsl_permutation_t *r_glsl_permutation;
958 /// storage for permutations linked in the hash table
959 memexpandablearray_t r_glsl_permutationarray;
961 static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, dpuint64 permutation)
963 //unsigned int hashdepth = 0;
964 unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
965 r_glsl_permutation_t *p;
966 for (p = r_glsl_permutationhash[mode][hashindex];p;p = p->hashnext)
968 if (p->mode == mode && p->permutation == permutation)
970 //if (hashdepth > 10)
971 // Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
976 p = (r_glsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_glsl_permutationarray);
978 p->permutation = permutation;
979 p->hashnext = r_glsl_permutationhash[mode][hashindex];
980 r_glsl_permutationhash[mode][hashindex] = p;
981 //if (hashdepth > 10)
982 // Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
986 static char *R_ShaderStrCat(const char **strings)
989 const char **p = strings;
992 for (p = strings;(t = *p);p++)
995 s = string = (char *)Mem_Alloc(r_main_mempool, len);
997 for (p = strings;(t = *p);p++)
1007 static char *R_ShaderStrCat(const char **strings);
1008 static void R_InitShaderModeInfo(void)
1011 shadermodeinfo_t *modeinfo;
1012 // we have a bunch of things to compute that weren't calculated at engine compile time - all filenames should have a crc of the builtin strings to prevent accidental overrides (any customization must be updated to match engine)
1013 for (language = 0; language < SHADERLANGUAGE_COUNT; language++)
1015 for (i = 0; i < SHADERMODE_COUNT; i++)
1017 char filename[MAX_QPATH];
1018 modeinfo = &shadermodeinfo[language][i];
1019 modeinfo->builtinstring = R_ShaderStrCat(modeinfo->builtinshaderstrings);
1020 modeinfo->builtincrc = CRC_Block((const unsigned char *)modeinfo->builtinstring, strlen(modeinfo->builtinstring));
1021 dpsnprintf(filename, sizeof(filename), "%s/%s_crc%i.%s", modeinfo->extension, modeinfo->sourcebasename, modeinfo->builtincrc, modeinfo->extension);
1022 modeinfo->filename = Mem_strdup(r_main_mempool, filename);
1027 static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qboolean printfromdisknotice, qboolean builtinonly)
1030 // if the mode has no filename we have to return the builtin string
1031 if (builtinonly || !modeinfo->filename)
1032 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1033 // note that FS_LoadFile appends a 0 byte to make it a valid string
1034 shaderstring = (char *)FS_LoadFile(modeinfo->filename, r_main_mempool, false, NULL);
1037 if (printfromdisknotice)
1038 Con_DPrintf("Loading shaders from file %s...\n", modeinfo->filename);
1039 return shaderstring;
1041 // fall back to builtinstring
1042 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1045 static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, dpuint64 permutation)
1050 shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode];
1052 char permutationname[256];
1053 int vertstrings_count = 0;
1054 int geomstrings_count = 0;
1055 int fragstrings_count = 0;
1056 const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1057 const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1058 const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1065 permutationname[0] = 0;
1066 sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false);
1068 strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
1070 // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object)
1071 if(vid.support.glshaderversion >= 140)
1073 vertstrings_list[vertstrings_count++] = "#version 140\n";
1074 geomstrings_list[geomstrings_count++] = "#version 140\n";
1075 fragstrings_list[fragstrings_count++] = "#version 140\n";
1076 vertstrings_list[vertstrings_count++] = "#define GLSL140\n";
1077 geomstrings_list[geomstrings_count++] = "#define GLSL140\n";
1078 fragstrings_list[fragstrings_count++] = "#define GLSL140\n";
1080 // if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad)
1081 else if(vid.support.glshaderversion >= 130)
1083 vertstrings_list[vertstrings_count++] = "#version 130\n";
1084 geomstrings_list[geomstrings_count++] = "#version 130\n";
1085 fragstrings_list[fragstrings_count++] = "#version 130\n";
1086 vertstrings_list[vertstrings_count++] = "#define GLSL130\n";
1087 geomstrings_list[geomstrings_count++] = "#define GLSL130\n";
1088 fragstrings_list[fragstrings_count++] = "#define GLSL130\n";
1090 // if we can do #version 120, we should (this adds the invariant keyword)
1091 else if(vid.support.glshaderversion >= 120)
1093 vertstrings_list[vertstrings_count++] = "#version 120\n";
1094 geomstrings_list[geomstrings_count++] = "#version 120\n";
1095 fragstrings_list[fragstrings_count++] = "#version 120\n";
1096 vertstrings_list[vertstrings_count++] = "#define GLSL120\n";
1097 geomstrings_list[geomstrings_count++] = "#define GLSL120\n";
1098 fragstrings_list[fragstrings_count++] = "#define GLSL120\n";
1100 // GLES also adds several things from GLSL120
1101 switch(vid.renderpath)
1103 case RENDERPATH_GLES2:
1104 vertstrings_list[vertstrings_count++] = "#define GLES\n";
1105 geomstrings_list[geomstrings_count++] = "#define GLES\n";
1106 fragstrings_list[fragstrings_count++] = "#define GLES\n";
1112 // the first pretext is which type of shader to compile as
1113 // (later these will all be bound together as a program object)
1114 vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
1115 geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
1116 fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
1118 // the second pretext is the mode (for example a light source)
1119 vertstrings_list[vertstrings_count++] = modeinfo->pretext;
1120 geomstrings_list[geomstrings_count++] = modeinfo->pretext;
1121 fragstrings_list[fragstrings_count++] = modeinfo->pretext;
1122 strlcat(permutationname, modeinfo->name, sizeof(permutationname));
1124 // now add all the permutation pretexts
1125 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1127 if (permutation & (1ll<<i))
1129 vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
1130 geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
1131 fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
1132 strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
1136 // keep line numbers correct
1137 vertstrings_list[vertstrings_count++] = "\n";
1138 geomstrings_list[geomstrings_count++] = "\n";
1139 fragstrings_list[fragstrings_count++] = "\n";
1144 R_CompileShader_AddStaticParms(mode, permutation);
1145 memcpy((char *)(vertstrings_list + vertstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1146 vertstrings_count += shaderstaticparms_count;
1147 memcpy((char *)(geomstrings_list + geomstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1148 geomstrings_count += shaderstaticparms_count;
1149 memcpy((char *)(fragstrings_list + fragstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1150 fragstrings_count += shaderstaticparms_count;
1152 // now append the shader text itself
1153 vertstrings_list[vertstrings_count++] = sourcestring;
1154 geomstrings_list[geomstrings_count++] = sourcestring;
1155 fragstrings_list[fragstrings_count++] = sourcestring;
1157 // compile the shader program
1158 if (vertstrings_count + geomstrings_count + fragstrings_count)
1159 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1163 qglUseProgram(p->program);CHECKGLERROR
1164 // look up all the uniform variable names we care about, so we don't
1165 // have to look them up every time we set them
1170 GLint activeuniformindex = 0;
1171 GLint numactiveuniforms = 0;
1172 char uniformname[128];
1173 GLsizei uniformnamelength = 0;
1174 GLint uniformsize = 0;
1175 GLenum uniformtype = 0;
1176 memset(uniformname, 0, sizeof(uniformname));
1177 qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms);
1178 Con_Printf("Shader has %i uniforms\n", numactiveuniforms);
1179 for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++)
1181 qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname);
1182 Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype);
1187 p->loc_Texture_First = qglGetUniformLocation(p->program, "Texture_First");
1188 p->loc_Texture_Second = qglGetUniformLocation(p->program, "Texture_Second");
1189 p->loc_Texture_GammaRamps = qglGetUniformLocation(p->program, "Texture_GammaRamps");
1190 p->loc_Texture_Normal = qglGetUniformLocation(p->program, "Texture_Normal");
1191 p->loc_Texture_Color = qglGetUniformLocation(p->program, "Texture_Color");
1192 p->loc_Texture_Gloss = qglGetUniformLocation(p->program, "Texture_Gloss");
1193 p->loc_Texture_Glow = qglGetUniformLocation(p->program, "Texture_Glow");
1194 p->loc_Texture_SecondaryNormal = qglGetUniformLocation(p->program, "Texture_SecondaryNormal");
1195 p->loc_Texture_SecondaryColor = qglGetUniformLocation(p->program, "Texture_SecondaryColor");
1196 p->loc_Texture_SecondaryGloss = qglGetUniformLocation(p->program, "Texture_SecondaryGloss");
1197 p->loc_Texture_SecondaryGlow = qglGetUniformLocation(p->program, "Texture_SecondaryGlow");
1198 p->loc_Texture_Pants = qglGetUniformLocation(p->program, "Texture_Pants");
1199 p->loc_Texture_Shirt = qglGetUniformLocation(p->program, "Texture_Shirt");
1200 p->loc_Texture_FogHeightTexture = qglGetUniformLocation(p->program, "Texture_FogHeightTexture");
1201 p->loc_Texture_FogMask = qglGetUniformLocation(p->program, "Texture_FogMask");
1202 p->loc_Texture_Lightmap = qglGetUniformLocation(p->program, "Texture_Lightmap");
1203 p->loc_Texture_Deluxemap = qglGetUniformLocation(p->program, "Texture_Deluxemap");
1204 p->loc_Texture_Attenuation = qglGetUniformLocation(p->program, "Texture_Attenuation");
1205 p->loc_Texture_Cube = qglGetUniformLocation(p->program, "Texture_Cube");
1206 p->loc_Texture_Refraction = qglGetUniformLocation(p->program, "Texture_Refraction");
1207 p->loc_Texture_Reflection = qglGetUniformLocation(p->program, "Texture_Reflection");
1208 p->loc_Texture_ShadowMap2D = qglGetUniformLocation(p->program, "Texture_ShadowMap2D");
1209 p->loc_Texture_CubeProjection = qglGetUniformLocation(p->program, "Texture_CubeProjection");
1210 p->loc_Texture_ScreenNormalMap = qglGetUniformLocation(p->program, "Texture_ScreenNormalMap");
1211 p->loc_Texture_ScreenDiffuse = qglGetUniformLocation(p->program, "Texture_ScreenDiffuse");
1212 p->loc_Texture_ScreenSpecular = qglGetUniformLocation(p->program, "Texture_ScreenSpecular");
1213 p->loc_Texture_ReflectMask = qglGetUniformLocation(p->program, "Texture_ReflectMask");
1214 p->loc_Texture_ReflectCube = qglGetUniformLocation(p->program, "Texture_ReflectCube");
1215 p->loc_Texture_BounceGrid = qglGetUniformLocation(p->program, "Texture_BounceGrid");
1216 p->loc_Alpha = qglGetUniformLocation(p->program, "Alpha");
1217 p->loc_BloomBlur_Parameters = qglGetUniformLocation(p->program, "BloomBlur_Parameters");
1218 p->loc_ClientTime = qglGetUniformLocation(p->program, "ClientTime");
1219 p->loc_Color_Ambient = qglGetUniformLocation(p->program, "Color_Ambient");
1220 p->loc_Color_Diffuse = qglGetUniformLocation(p->program, "Color_Diffuse");
1221 p->loc_Color_Specular = qglGetUniformLocation(p->program, "Color_Specular");
1222 p->loc_Color_Glow = qglGetUniformLocation(p->program, "Color_Glow");
1223 p->loc_Color_Pants = qglGetUniformLocation(p->program, "Color_Pants");
1224 p->loc_Color_Shirt = qglGetUniformLocation(p->program, "Color_Shirt");
1225 p->loc_DeferredColor_Ambient = qglGetUniformLocation(p->program, "DeferredColor_Ambient");
1226 p->loc_DeferredColor_Diffuse = qglGetUniformLocation(p->program, "DeferredColor_Diffuse");
1227 p->loc_DeferredColor_Specular = qglGetUniformLocation(p->program, "DeferredColor_Specular");
1228 p->loc_DeferredMod_Diffuse = qglGetUniformLocation(p->program, "DeferredMod_Diffuse");
1229 p->loc_DeferredMod_Specular = qglGetUniformLocation(p->program, "DeferredMod_Specular");
1230 p->loc_DistortScaleRefractReflect = qglGetUniformLocation(p->program, "DistortScaleRefractReflect");
1231 p->loc_EyePosition = qglGetUniformLocation(p->program, "EyePosition");
1232 p->loc_FogColor = qglGetUniformLocation(p->program, "FogColor");
1233 p->loc_FogHeightFade = qglGetUniformLocation(p->program, "FogHeightFade");
1234 p->loc_FogPlane = qglGetUniformLocation(p->program, "FogPlane");
1235 p->loc_FogPlaneViewDist = qglGetUniformLocation(p->program, "FogPlaneViewDist");
1236 p->loc_FogRangeRecip = qglGetUniformLocation(p->program, "FogRangeRecip");
1237 p->loc_LightColor = qglGetUniformLocation(p->program, "LightColor");
1238 p->loc_LightDir = qglGetUniformLocation(p->program, "LightDir");
1239 p->loc_LightPosition = qglGetUniformLocation(p->program, "LightPosition");
1240 p->loc_OffsetMapping_ScaleSteps = qglGetUniformLocation(p->program, "OffsetMapping_ScaleSteps");
1241 p->loc_OffsetMapping_LodDistance = qglGetUniformLocation(p->program, "OffsetMapping_LodDistance");
1242 p->loc_OffsetMapping_Bias = qglGetUniformLocation(p->program, "OffsetMapping_Bias");
1243 p->loc_PixelSize = qglGetUniformLocation(p->program, "PixelSize");
1244 p->loc_ReflectColor = qglGetUniformLocation(p->program, "ReflectColor");
1245 p->loc_ReflectFactor = qglGetUniformLocation(p->program, "ReflectFactor");
1246 p->loc_ReflectOffset = qglGetUniformLocation(p->program, "ReflectOffset");
1247 p->loc_RefractColor = qglGetUniformLocation(p->program, "RefractColor");
1248 p->loc_Saturation = qglGetUniformLocation(p->program, "Saturation");
1249 p->loc_ScreenCenterRefractReflect = qglGetUniformLocation(p->program, "ScreenCenterRefractReflect");
1250 p->loc_ScreenScaleRefractReflect = qglGetUniformLocation(p->program, "ScreenScaleRefractReflect");
1251 p->loc_ScreenToDepth = qglGetUniformLocation(p->program, "ScreenToDepth");
1252 p->loc_ShadowMap_Parameters = qglGetUniformLocation(p->program, "ShadowMap_Parameters");
1253 p->loc_ShadowMap_TextureScale = qglGetUniformLocation(p->program, "ShadowMap_TextureScale");
1254 p->loc_SpecularPower = qglGetUniformLocation(p->program, "SpecularPower");
1255 p->loc_UserVec1 = qglGetUniformLocation(p->program, "UserVec1");
1256 p->loc_UserVec2 = qglGetUniformLocation(p->program, "UserVec2");
1257 p->loc_UserVec3 = qglGetUniformLocation(p->program, "UserVec3");
1258 p->loc_UserVec4 = qglGetUniformLocation(p->program, "UserVec4");
1259 p->loc_ViewTintColor = qglGetUniformLocation(p->program, "ViewTintColor");
1260 p->loc_ViewToLight = qglGetUniformLocation(p->program, "ViewToLight");
1261 p->loc_ModelToLight = qglGetUniformLocation(p->program, "ModelToLight");
1262 p->loc_TexMatrix = qglGetUniformLocation(p->program, "TexMatrix");
1263 p->loc_BackgroundTexMatrix = qglGetUniformLocation(p->program, "BackgroundTexMatrix");
1264 p->loc_ModelViewMatrix = qglGetUniformLocation(p->program, "ModelViewMatrix");
1265 p->loc_ModelViewProjectionMatrix = qglGetUniformLocation(p->program, "ModelViewProjectionMatrix");
1266 p->loc_PixelToScreenTexCoord = qglGetUniformLocation(p->program, "PixelToScreenTexCoord");
1267 p->loc_ModelToReflectCube = qglGetUniformLocation(p->program, "ModelToReflectCube");
1268 p->loc_ShadowMapMatrix = qglGetUniformLocation(p->program, "ShadowMapMatrix");
1269 p->loc_BloomColorSubtract = qglGetUniformLocation(p->program, "BloomColorSubtract");
1270 p->loc_NormalmapScrollBlend = qglGetUniformLocation(p->program, "NormalmapScrollBlend");
1271 p->loc_BounceGridMatrix = qglGetUniformLocation(p->program, "BounceGridMatrix");
1272 p->loc_BounceGridIntensity = qglGetUniformLocation(p->program, "BounceGridIntensity");
1273 // initialize the samplers to refer to the texture units we use
1274 p->tex_Texture_First = -1;
1275 p->tex_Texture_Second = -1;
1276 p->tex_Texture_GammaRamps = -1;
1277 p->tex_Texture_Normal = -1;
1278 p->tex_Texture_Color = -1;
1279 p->tex_Texture_Gloss = -1;
1280 p->tex_Texture_Glow = -1;
1281 p->tex_Texture_SecondaryNormal = -1;
1282 p->tex_Texture_SecondaryColor = -1;
1283 p->tex_Texture_SecondaryGloss = -1;
1284 p->tex_Texture_SecondaryGlow = -1;
1285 p->tex_Texture_Pants = -1;
1286 p->tex_Texture_Shirt = -1;
1287 p->tex_Texture_FogHeightTexture = -1;
1288 p->tex_Texture_FogMask = -1;
1289 p->tex_Texture_Lightmap = -1;
1290 p->tex_Texture_Deluxemap = -1;
1291 p->tex_Texture_Attenuation = -1;
1292 p->tex_Texture_Cube = -1;
1293 p->tex_Texture_Refraction = -1;
1294 p->tex_Texture_Reflection = -1;
1295 p->tex_Texture_ShadowMap2D = -1;
1296 p->tex_Texture_CubeProjection = -1;
1297 p->tex_Texture_ScreenNormalMap = -1;
1298 p->tex_Texture_ScreenDiffuse = -1;
1299 p->tex_Texture_ScreenSpecular = -1;
1300 p->tex_Texture_ReflectMask = -1;
1301 p->tex_Texture_ReflectCube = -1;
1302 p->tex_Texture_BounceGrid = -1;
1303 // bind the texture samplers in use
1305 if (p->loc_Texture_First >= 0) {p->tex_Texture_First = sampler;qglUniform1i(p->loc_Texture_First , sampler);sampler++;}
1306 if (p->loc_Texture_Second >= 0) {p->tex_Texture_Second = sampler;qglUniform1i(p->loc_Texture_Second , sampler);sampler++;}
1307 if (p->loc_Texture_GammaRamps >= 0) {p->tex_Texture_GammaRamps = sampler;qglUniform1i(p->loc_Texture_GammaRamps , sampler);sampler++;}
1308 if (p->loc_Texture_Normal >= 0) {p->tex_Texture_Normal = sampler;qglUniform1i(p->loc_Texture_Normal , sampler);sampler++;}
1309 if (p->loc_Texture_Color >= 0) {p->tex_Texture_Color = sampler;qglUniform1i(p->loc_Texture_Color , sampler);sampler++;}
1310 if (p->loc_Texture_Gloss >= 0) {p->tex_Texture_Gloss = sampler;qglUniform1i(p->loc_Texture_Gloss , sampler);sampler++;}
1311 if (p->loc_Texture_Glow >= 0) {p->tex_Texture_Glow = sampler;qglUniform1i(p->loc_Texture_Glow , sampler);sampler++;}
1312 if (p->loc_Texture_SecondaryNormal >= 0) {p->tex_Texture_SecondaryNormal = sampler;qglUniform1i(p->loc_Texture_SecondaryNormal , sampler);sampler++;}
1313 if (p->loc_Texture_SecondaryColor >= 0) {p->tex_Texture_SecondaryColor = sampler;qglUniform1i(p->loc_Texture_SecondaryColor , sampler);sampler++;}
1314 if (p->loc_Texture_SecondaryGloss >= 0) {p->tex_Texture_SecondaryGloss = sampler;qglUniform1i(p->loc_Texture_SecondaryGloss , sampler);sampler++;}
1315 if (p->loc_Texture_SecondaryGlow >= 0) {p->tex_Texture_SecondaryGlow = sampler;qglUniform1i(p->loc_Texture_SecondaryGlow , sampler);sampler++;}
1316 if (p->loc_Texture_Pants >= 0) {p->tex_Texture_Pants = sampler;qglUniform1i(p->loc_Texture_Pants , sampler);sampler++;}
1317 if (p->loc_Texture_Shirt >= 0) {p->tex_Texture_Shirt = sampler;qglUniform1i(p->loc_Texture_Shirt , sampler);sampler++;}
1318 if (p->loc_Texture_FogHeightTexture>= 0) {p->tex_Texture_FogHeightTexture = sampler;qglUniform1i(p->loc_Texture_FogHeightTexture, sampler);sampler++;}
1319 if (p->loc_Texture_FogMask >= 0) {p->tex_Texture_FogMask = sampler;qglUniform1i(p->loc_Texture_FogMask , sampler);sampler++;}
1320 if (p->loc_Texture_Lightmap >= 0) {p->tex_Texture_Lightmap = sampler;qglUniform1i(p->loc_Texture_Lightmap , sampler);sampler++;}
1321 if (p->loc_Texture_Deluxemap >= 0) {p->tex_Texture_Deluxemap = sampler;qglUniform1i(p->loc_Texture_Deluxemap , sampler);sampler++;}
1322 if (p->loc_Texture_Attenuation >= 0) {p->tex_Texture_Attenuation = sampler;qglUniform1i(p->loc_Texture_Attenuation , sampler);sampler++;}
1323 if (p->loc_Texture_Cube >= 0) {p->tex_Texture_Cube = sampler;qglUniform1i(p->loc_Texture_Cube , sampler);sampler++;}
1324 if (p->loc_Texture_Refraction >= 0) {p->tex_Texture_Refraction = sampler;qglUniform1i(p->loc_Texture_Refraction , sampler);sampler++;}
1325 if (p->loc_Texture_Reflection >= 0) {p->tex_Texture_Reflection = sampler;qglUniform1i(p->loc_Texture_Reflection , sampler);sampler++;}
1326 if (p->loc_Texture_ShadowMap2D >= 0) {p->tex_Texture_ShadowMap2D = sampler;qglUniform1i(p->loc_Texture_ShadowMap2D , sampler);sampler++;}
1327 if (p->loc_Texture_CubeProjection >= 0) {p->tex_Texture_CubeProjection = sampler;qglUniform1i(p->loc_Texture_CubeProjection , sampler);sampler++;}
1328 if (p->loc_Texture_ScreenNormalMap >= 0) {p->tex_Texture_ScreenNormalMap = sampler;qglUniform1i(p->loc_Texture_ScreenNormalMap , sampler);sampler++;}
1329 if (p->loc_Texture_ScreenDiffuse >= 0) {p->tex_Texture_ScreenDiffuse = sampler;qglUniform1i(p->loc_Texture_ScreenDiffuse , sampler);sampler++;}
1330 if (p->loc_Texture_ScreenSpecular >= 0) {p->tex_Texture_ScreenSpecular = sampler;qglUniform1i(p->loc_Texture_ScreenSpecular , sampler);sampler++;}
1331 if (p->loc_Texture_ReflectMask >= 0) {p->tex_Texture_ReflectMask = sampler;qglUniform1i(p->loc_Texture_ReflectMask , sampler);sampler++;}
1332 if (p->loc_Texture_ReflectCube >= 0) {p->tex_Texture_ReflectCube = sampler;qglUniform1i(p->loc_Texture_ReflectCube , sampler);sampler++;}
1333 if (p->loc_Texture_BounceGrid >= 0) {p->tex_Texture_BounceGrid = sampler;qglUniform1i(p->loc_Texture_BounceGrid , sampler);sampler++;}
1334 // get the uniform block indices so we can bind them
1335 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1336 if (vid.support.arb_uniform_buffer_object)
1337 p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
1340 p->ubiloc_Skeletal_Transform12_UniformBlock = -1;
1341 // clear the uniform block bindings
1342 p->ubibind_Skeletal_Transform12_UniformBlock = -1;
1343 // bind the uniform blocks in use
1345 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1346 if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;}
1348 // we're done compiling and setting up the shader, at least until it is used
1350 Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler);
1353 Con_Printf("^1GLSL shader %s failed! some features may not work properly.\n", permutationname);
1357 Mem_Free(sourcestring);
1360 static void R_SetupShader_SetPermutationGLSL(unsigned int mode, dpuint64 permutation)
1362 r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation);
1363 if (r_glsl_permutation != perm)
1365 r_glsl_permutation = perm;
1366 if (!r_glsl_permutation->program)
1368 if (!r_glsl_permutation->compiled)
1370 Con_DPrintf("Compiling shader mode %u permutation %u\n", mode, permutation);
1371 R_GLSL_CompilePermutation(perm, mode, permutation);
1373 if (!r_glsl_permutation->program)
1375 // remove features until we find a valid permutation
1377 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1379 // reduce i more quickly whenever it would not remove any bits
1380 dpuint64 j = 1ll<<(SHADERPERMUTATION_COUNT-1-i);
1381 if (!(permutation & j))
1384 r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1385 if (!r_glsl_permutation->compiled)
1386 R_GLSL_CompilePermutation(perm, mode, permutation);
1387 if (r_glsl_permutation->program)
1390 if (i >= SHADERPERMUTATION_COUNT)
1392 //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext);
1393 r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1394 qglUseProgram(0);CHECKGLERROR
1395 return; // no bit left to clear, entire mode is broken
1400 qglUseProgram(r_glsl_permutation->program);CHECKGLERROR
1402 if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
1403 if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
1404 if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time);
1408 void R_GLSL_Restart_f(void)
1410 unsigned int i, limit;
1411 switch(vid.renderpath)
1413 case RENDERPATH_GL20:
1414 case RENDERPATH_GLES2:
1416 r_glsl_permutation_t *p;
1417 r_glsl_permutation = NULL;
1418 limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
1419 for (i = 0;i < limit;i++)
1421 if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
1423 GL_Backend_FreeProgram(p->program);
1424 Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
1427 memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
1433 static void R_GLSL_DumpShader_f(void)
1435 int i, language, mode, dupe;
1437 shadermodeinfo_t *modeinfo;
1440 for (language = 0;language < SHADERLANGUAGE_COUNT;language++)
1442 modeinfo = shadermodeinfo[language];
1443 for (mode = 0;mode < SHADERMODE_COUNT;mode++)
1445 // don't dump the same file multiple times (most or all shaders come from the same file)
1446 for (dupe = mode - 1;dupe >= 0;dupe--)
1447 if (!strcmp(modeinfo[mode].filename, modeinfo[dupe].filename))
1451 text = modeinfo[mode].builtinstring;
1454 file = FS_OpenRealFile(modeinfo[mode].filename, "w", false);
1457 FS_Print(file, "/* The engine may define the following macros:\n");
1458 FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
1459 for (i = 0;i < SHADERMODE_COUNT;i++)
1460 FS_Print(file, modeinfo[i].pretext);
1461 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1462 FS_Print(file, shaderpermutationinfo[i].pretext);
1463 FS_Print(file, "*/\n");
1464 FS_Print(file, text);
1466 Con_Printf("%s written\n", modeinfo[mode].filename);
1469 Con_Printf("failed to write to %s\n", modeinfo[mode].filename);
1474 void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemode, int rgbscale, qboolean usegamma, qboolean notrippy, qboolean suppresstexalpha)
1476 dpuint64 permutation = 0;
1477 if (r_trippy.integer && !notrippy)
1478 permutation |= SHADERPERMUTATION_TRIPPY;
1479 permutation |= SHADERPERMUTATION_VIEWTINT;
1481 permutation |= SHADERPERMUTATION_DIFFUSE;
1483 permutation |= SHADERPERMUTATION_SPECULAR;
1484 if (texturemode == GL_MODULATE)
1485 permutation |= SHADERPERMUTATION_COLORMAPPING;
1486 else if (texturemode == GL_ADD)
1487 permutation |= SHADERPERMUTATION_GLOW;
1488 else if (texturemode == GL_DECAL)
1489 permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1490 if (usegamma && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
1491 permutation |= SHADERPERMUTATION_GAMMARAMPS;
1492 if (suppresstexalpha)
1493 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1495 texturemode = GL_MODULATE;
1496 if (vid.allowalphatocoverage)
1497 GL_AlphaToCoverage(false);
1498 switch (vid.renderpath)
1500 case RENDERPATH_GL20:
1501 case RENDERPATH_GLES2:
1502 R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation);
1503 if (r_glsl_permutation->tex_Texture_First >= 0)
1504 R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , first );
1505 if (r_glsl_permutation->tex_Texture_Second >= 0)
1506 R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second, second);
1507 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0)
1508 R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps);
1513 void R_SetupShader_Generic_NoTexture(qboolean usegamma, qboolean notrippy)
1515 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, usegamma, notrippy, false);
1518 void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb, qboolean skeletal)
1520 dpuint64 permutation = 0;
1521 if (r_trippy.integer && !notrippy)
1522 permutation |= SHADERPERMUTATION_TRIPPY;
1524 permutation |= SHADERPERMUTATION_DEPTHRGB;
1526 permutation |= SHADERPERMUTATION_SKELETAL;
1528 if (vid.allowalphatocoverage)
1529 GL_AlphaToCoverage(false);
1530 switch (vid.renderpath)
1532 case RENDERPATH_GL20:
1533 case RENDERPATH_GLES2:
1534 R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
1535 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1536 if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
1542 #define BLENDFUNC_ALLOWS_COLORMOD 1
1543 #define BLENDFUNC_ALLOWS_FOG 2
1544 #define BLENDFUNC_ALLOWS_FOG_HACK0 4
1545 #define BLENDFUNC_ALLOWS_FOG_HACKALPHA 8
1546 #define BLENDFUNC_ALLOWS_ANYFOG (BLENDFUNC_ALLOWS_FOG | BLENDFUNC_ALLOWS_FOG_HACK0 | BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1547 static int R_BlendFuncFlags(int src, int dst)
1551 // a blendfunc allows colormod if:
1552 // a) it can never keep the destination pixel invariant, or
1553 // b) it can keep the destination pixel invariant, and still can do so if colormodded
1554 // this is to prevent unintended side effects from colormod
1556 // a blendfunc allows fog if:
1557 // blend(fog(src), fog(dst)) == fog(blend(src, dst))
1558 // this is to prevent unintended side effects from fog
1560 // these checks are the output of fogeval.pl
1562 r |= BLENDFUNC_ALLOWS_COLORMOD;
1563 if(src == GL_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1564 if(src == GL_DST_ALPHA && dst == GL_ONE_MINUS_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1565 if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1566 if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1567 if(src == GL_DST_COLOR && dst == GL_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1568 if(src == GL_DST_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1569 if(src == GL_DST_COLOR && dst == GL_ZERO) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1570 if(src == GL_ONE && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1571 if(src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG_HACKALPHA;
1572 if(src == GL_ONE && dst == GL_ZERO) r |= BLENDFUNC_ALLOWS_FOG;
1573 if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1574 if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1575 if(src == GL_ONE_MINUS_DST_COLOR && dst == GL_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1576 if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1577 if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1578 if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1579 if(src == GL_ONE_MINUS_SRC_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1580 if(src == GL_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1581 if(src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1582 if(src == GL_ZERO && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG;
1583 if(src == GL_ZERO && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1588 void R_SetupShader_Surface(const float rtlightambient[3], const float rtlightdiffuse[3], const float rtlightspecular[3], rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist, void *surfacewaterplane, qboolean notrippy)
1590 // select a permutation of the lighting shader appropriate to this
1591 // combination of texture, entity, light source, and fogging, only use the
1592 // minimum features necessary to avoid wasting rendering time in the
1593 // fragment shader on features that are not being used
1594 dpuint64 permutation = 0;
1595 unsigned int mode = 0;
1597 texture_t *t = rsurface.texture;
1599 matrix4x4_t tempmatrix;
1600 r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
1601 if (r_trippy.integer && !notrippy)
1602 permutation |= SHADERPERMUTATION_TRIPPY;
1603 if (t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1604 permutation |= SHADERPERMUTATION_ALPHAKILL;
1605 if (t->currentmaterialflags & MATERIALFLAG_OCCLUDE)
1606 permutation |= SHADERPERMUTATION_OCCLUDE;
1607 if (t->r_water_waterscroll[0] && t->r_water_waterscroll[1])
1608 permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
1609 if (rsurfacepass == RSURFPASS_BACKGROUND)
1611 // distorted background
1612 if (t->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1614 mode = SHADERMODE_WATER;
1615 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1616 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1617 if((r_wateralpha.value < 1) && (t->currentmaterialflags & MATERIALFLAG_WATERALPHA))
1619 // this is the right thing to do for wateralpha
1620 GL_BlendFunc(GL_ONE, GL_ZERO);
1621 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1625 // this is the right thing to do for entity alpha
1626 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1627 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1630 else if (t->currentmaterialflags & MATERIALFLAG_REFRACTION)
1632 mode = SHADERMODE_REFRACTION;
1633 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1634 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1635 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1636 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1640 mode = SHADERMODE_GENERIC;
1641 permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL;
1642 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1643 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1645 if (vid.allowalphatocoverage)
1646 GL_AlphaToCoverage(false);
1648 else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
1650 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1652 switch(t->offsetmapping)
1654 case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1655 case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1656 case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1657 case OFFSETMAPPING_OFF: break;
1660 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1661 permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1662 // normalmap (deferred prepass), may use alpha test on diffuse
1663 mode = SHADERMODE_DEFERREDGEOMETRY;
1664 GL_BlendFunc(GL_ONE, GL_ZERO);
1665 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1666 if (vid.allowalphatocoverage)
1667 GL_AlphaToCoverage(false);
1669 else if (rsurfacepass == RSURFPASS_RTLIGHT)
1671 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1673 switch(t->offsetmapping)
1675 case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1676 case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1677 case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1678 case OFFSETMAPPING_OFF: break;
1681 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1682 permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1683 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1684 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1686 mode = SHADERMODE_LIGHTSOURCE;
1687 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1688 permutation |= SHADERPERMUTATION_CUBEFILTER;
1689 if (VectorLength2(rtlightdiffuse) > 0)
1690 permutation |= SHADERPERMUTATION_DIFFUSE;
1691 if (VectorLength2(rtlightspecular) > 0)
1692 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1693 if (r_refdef.fogenabled)
1694 permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1695 if (t->colormapping)
1696 permutation |= SHADERPERMUTATION_COLORMAPPING;
1697 if (r_shadow_usingshadowmap2d)
1699 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1700 if(r_shadow_shadowmapvsdct)
1701 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
1703 if (r_shadow_shadowmap2ddepthbuffer)
1704 permutation |= SHADERPERMUTATION_DEPTHRGB;
1706 if (t->reflectmasktexture)
1707 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1708 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1709 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE);
1710 if (vid.allowalphatocoverage)
1711 GL_AlphaToCoverage(false);
1713 else if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
1715 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1717 switch(t->offsetmapping)
1719 case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1720 case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1721 case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1722 case OFFSETMAPPING_OFF: break;
1725 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1726 permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1727 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1728 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1729 // directional model lighting
1730 mode = SHADERMODE_LIGHTDIRECTION;
1731 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1732 permutation |= SHADERPERMUTATION_GLOW;
1733 if (VectorLength2(t->render_modellight_diffuse))
1734 permutation |= SHADERPERMUTATION_DIFFUSE;
1735 if (VectorLength2(t->render_modellight_specular) > 0)
1736 permutation |= SHADERPERMUTATION_SPECULAR;
1737 if (r_refdef.fogenabled)
1738 permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1739 if (t->colormapping)
1740 permutation |= SHADERPERMUTATION_COLORMAPPING;
1741 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1743 permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1744 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1746 if (r_shadow_shadowmap2ddepthbuffer)
1747 permutation |= SHADERPERMUTATION_DEPTHRGB;
1749 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1750 permutation |= SHADERPERMUTATION_REFLECTION;
1751 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1752 permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1753 if (t->reflectmasktexture)
1754 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1755 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld)
1757 permutation |= SHADERPERMUTATION_BOUNCEGRID;
1758 if (r_shadow_bouncegrid_state.directional)
1759 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1761 GL_BlendFunc(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1762 blendfuncflags = R_BlendFuncFlags(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1763 // when using alphatocoverage, we don't need alphakill
1764 if (vid.allowalphatocoverage)
1766 if (r_transparent_alphatocoverage.integer)
1768 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1769 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1772 GL_AlphaToCoverage(false);
1777 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1779 switch(t->offsetmapping)
1781 case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1782 case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1783 case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1784 case OFFSETMAPPING_OFF: break;
1787 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1788 permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1789 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1790 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1792 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1793 permutation |= SHADERPERMUTATION_GLOW;
1794 if (r_refdef.fogenabled)
1795 permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1796 if (t->colormapping)
1797 permutation |= SHADERPERMUTATION_COLORMAPPING;
1798 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1800 permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1801 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1803 if (r_shadow_shadowmap2ddepthbuffer)
1804 permutation |= SHADERPERMUTATION_DEPTHRGB;
1806 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1807 permutation |= SHADERPERMUTATION_REFLECTION;
1808 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1809 permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1810 if (t->reflectmasktexture)
1811 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1812 if (FAKELIGHT_ENABLED)
1814 // fake lightmapping (q1bsp, q3bsp, fullbright map)
1815 mode = SHADERMODE_FAKELIGHT;
1816 permutation |= SHADERPERMUTATION_DIFFUSE;
1817 if (VectorLength2(t->render_lightmap_specular) > 0)
1818 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1820 else if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
1822 // deluxemapping (light direction texture)
1823 if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace)
1824 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1826 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1827 permutation |= SHADERPERMUTATION_DIFFUSE;
1828 if (VectorLength2(t->render_lightmap_specular) > 0)
1829 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1831 else if (r_glsl_deluxemapping.integer >= 2)
1833 // fake deluxemapping (uniform light direction in tangentspace)
1834 if (rsurface.uselightmaptexture)
1835 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP;
1837 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR;
1838 permutation |= SHADERPERMUTATION_DIFFUSE;
1839 if (VectorLength2(t->render_lightmap_specular) > 0)
1840 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1842 else if (rsurface.uselightmaptexture)
1844 // ordinary lightmapping (q1bsp, q3bsp)
1845 mode = SHADERMODE_LIGHTMAP;
1849 // ordinary vertex coloring (q3bsp)
1850 mode = SHADERMODE_VERTEXCOLOR;
1852 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld)
1854 permutation |= SHADERPERMUTATION_BOUNCEGRID;
1855 if (r_shadow_bouncegrid_state.directional)
1856 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1858 GL_BlendFunc(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1859 blendfuncflags = R_BlendFuncFlags(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1860 // when using alphatocoverage, we don't need alphakill
1861 if (vid.allowalphatocoverage)
1863 if (r_transparent_alphatocoverage.integer)
1865 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1866 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1869 GL_AlphaToCoverage(false);
1872 if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG))
1873 permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE);
1874 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1875 permutation |= SHADERPERMUTATION_FOGALPHAHACK;
1876 switch(vid.renderpath)
1878 case RENDERPATH_GL20:
1879 case RENDERPATH_GLES2:
1880 if (!vid.useinterleavedarrays)
1882 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | (rsurface.modellightmapcolor4f ? BATCHNEED_ARRAY_VERTEXCOLOR : 0) | BATCHNEED_ARRAY_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_ARRAY_LIGHTMAP : 0) | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
1883 R_Mesh_VertexPointer( 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
1884 R_Mesh_ColorPointer( 4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
1885 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
1886 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
1887 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
1888 R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
1889 R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
1890 R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
1891 R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
1892 R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
1896 RSurf_PrepareVerticesForBatch(BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | (rsurface.modellightmapcolor4f ? BATCHNEED_VERTEXMESH_VERTEXCOLOR : 0) | BATCHNEED_VERTEXMESH_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_VERTEXMESH_LIGHTMAP : 0) | (rsurface.entityskeletaltransform3x4 ? BATCHNEED_VERTEXMESH_SKELETAL : 0) | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
1897 R_Mesh_PrepareVertices_Mesh(rsurface.batchnumvertices, rsurface.batchvertexmesh, rsurface.batchvertexmesh_vertexbuffer, rsurface.batchvertexmesh_bufferoffset);
1899 // this has to be after RSurf_PrepareVerticesForBatch
1900 if (rsurface.batchskeletaltransform3x4buffer)
1901 permutation |= SHADERPERMUTATION_SKELETAL;
1902 R_SetupShader_SetPermutationGLSL(mode, permutation);
1903 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1904 if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
1906 if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
1907 if (mode == SHADERMODE_LIGHTSOURCE)
1909 if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
1910 if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1911 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1912 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
1913 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
1914 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
1916 // additive passes are only darkened by fog, not tinted
1917 if (r_glsl_permutation->loc_FogColor >= 0)
1918 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1919 if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, t->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
1923 if (mode == SHADERMODE_FLATCOLOR)
1925 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
1927 else if (mode == SHADERMODE_LIGHTDIRECTION)
1929 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
1930 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_modellight_diffuse[0], t->render_modellight_diffuse[1], t->render_modellight_diffuse[2]);
1931 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_modellight_specular[0], t->render_modellight_specular[1], t->render_modellight_specular[2]);
1932 if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, t->render_rtlight_diffuse[0], t->render_rtlight_diffuse[1], t->render_rtlight_diffuse[2]);
1933 if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, t->render_rtlight_specular[0], t->render_rtlight_specular[1], t->render_rtlight_specular[2]);
1934 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1935 if (r_glsl_permutation->loc_LightDir >= 0) qglUniform3f(r_glsl_permutation->loc_LightDir, t->render_modellight_lightdir[0], t->render_modellight_lightdir[1], t->render_modellight_lightdir[2]);
1939 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_lightmap_ambient[0], t->render_lightmap_ambient[1], t->render_lightmap_ambient[2]);
1940 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_lightmap_diffuse[0], t->render_lightmap_diffuse[1], t->render_lightmap_diffuse[2]);
1941 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_lightmap_specular[0], t->render_lightmap_specular[1], t->render_lightmap_specular[2]);
1942 if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, t->render_rtlight_diffuse[0], t->render_rtlight_diffuse[1], t->render_rtlight_diffuse[2]);
1943 if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, t->render_rtlight_specular[0], t->render_rtlight_specular[1], t->render_rtlight_specular[2]);
1945 // additive passes are only darkened by fog, not tinted
1946 if (r_glsl_permutation->loc_FogColor >= 0)
1948 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
1949 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1951 qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1953 if (r_glsl_permutation->loc_DistortScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_DistortScaleRefractReflect, r_water_refractdistort.value * t->refractfactor, r_water_refractdistort.value * t->refractfactor, r_water_reflectdistort.value * t->reflectfactor, r_water_reflectdistort.value * t->reflectfactor);
1954 if (r_glsl_permutation->loc_ScreenScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenScaleRefractReflect, r_fb.water.screenscale[0], r_fb.water.screenscale[1], r_fb.water.screenscale[0], r_fb.water.screenscale[1]);
1955 if (r_glsl_permutation->loc_ScreenCenterRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenCenterRefractReflect, r_fb.water.screencenter[0], r_fb.water.screencenter[1], r_fb.water.screencenter[0], r_fb.water.screencenter[1]);
1956 if (r_glsl_permutation->loc_RefractColor >= 0) qglUniform4f(r_glsl_permutation->loc_RefractColor, t->refractcolor4f[0], t->refractcolor4f[1], t->refractcolor4f[2], t->refractcolor4f[3] * t->currentalpha);
1957 if (r_glsl_permutation->loc_ReflectColor >= 0) qglUniform4f(r_glsl_permutation->loc_ReflectColor, t->reflectcolor4f[0], t->reflectcolor4f[1], t->reflectcolor4f[2], t->reflectcolor4f[3] * t->currentalpha);
1958 if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, t->reflectmax - t->reflectmin);
1959 if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, t->reflectmin);
1960 if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, t->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
1961 if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
1963 if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
1964 if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
1965 if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
1966 if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
1968 if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_modelshadowmap_texturescale[0], r_shadow_modelshadowmap_texturescale[1], r_shadow_modelshadowmap_texturescale[2], r_shadow_modelshadowmap_texturescale[3]);
1969 if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_modelshadowmap_parameters[0], r_shadow_modelshadowmap_parameters[1], r_shadow_modelshadowmap_parameters[2], r_shadow_modelshadowmap_parameters[3]);
1973 if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
1974 if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
1977 if (r_glsl_permutation->loc_Color_Glow >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Glow, t->render_glowmod[0], t->render_glowmod[1], t->render_glowmod[2]);
1978 if (r_glsl_permutation->loc_Alpha >= 0) qglUniform1f(r_glsl_permutation->loc_Alpha, t->currentalpha * ((t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? t->r_water_wateralpha : 1));
1979 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
1980 if (r_glsl_permutation->loc_Color_Pants >= 0)
1982 if (t->pantstexture)
1983 qglUniform3f(r_glsl_permutation->loc_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
1985 qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
1987 if (r_glsl_permutation->loc_Color_Shirt >= 0)
1989 if (t->shirttexture)
1990 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
1992 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
1994 if (r_glsl_permutation->loc_FogPlane >= 0) qglUniform4f(r_glsl_permutation->loc_FogPlane, rsurface.fogplane[0], rsurface.fogplane[1], rsurface.fogplane[2], rsurface.fogplane[3]);
1995 if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
1996 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
1997 if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
1998 if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps,
1999 r_glsl_offsetmapping_scale.value*t->offsetscale,
2000 max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2001 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2002 max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
2004 if (r_glsl_permutation->loc_OffsetMapping_LodDistance >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer * r_refdef.view.quality);
2005 if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, t->offsetbias);
2006 if (r_glsl_permutation->loc_ScreenToDepth >= 0) qglUniform2f(r_glsl_permutation->loc_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
2007 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
2008 if (r_glsl_permutation->loc_BounceGridMatrix >= 0) {Matrix4x4_Concat(&tempmatrix, &r_shadow_bouncegrid_state.matrix, &rsurface.matrix);Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BounceGridMatrix, 1, false, m16f);}
2009 if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
2011 if (r_glsl_permutation->tex_Texture_First >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , r_texture_white );
2012 if (r_glsl_permutation->tex_Texture_Second >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second , r_texture_white );
2013 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps , r_texture_gammaramps );
2014 if (r_glsl_permutation->tex_Texture_Normal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal , t->nmaptexture );
2015 if (r_glsl_permutation->tex_Texture_Color >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color , t->basetexture );
2016 if (r_glsl_permutation->tex_Texture_Gloss >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss , t->glosstexture );
2017 if (r_glsl_permutation->tex_Texture_Glow >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow , t->glowtexture );
2018 if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal , t->backgroundnmaptexture );
2019 if (r_glsl_permutation->tex_Texture_SecondaryColor >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor , t->backgroundbasetexture );
2020 if (r_glsl_permutation->tex_Texture_SecondaryGloss >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss , t->backgroundglosstexture );
2021 if (r_glsl_permutation->tex_Texture_SecondaryGlow >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow , t->backgroundglowtexture );
2022 if (r_glsl_permutation->tex_Texture_Pants >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants , t->pantstexture );
2023 if (r_glsl_permutation->tex_Texture_Shirt >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt , t->shirttexture );
2024 if (r_glsl_permutation->tex_Texture_ReflectMask >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask , t->reflectmasktexture );
2025 if (r_glsl_permutation->tex_Texture_ReflectCube >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
2026 if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture );
2027 if (r_glsl_permutation->tex_Texture_FogMask >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask , r_texture_fogattenuation );
2028 if (r_glsl_permutation->tex_Texture_Lightmap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
2029 if (r_glsl_permutation->tex_Texture_Deluxemap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Deluxemap , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap);
2030 if (r_glsl_permutation->tex_Texture_Attenuation >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation , r_shadow_attenuationgradienttexture );
2031 if (rsurfacepass == RSURFPASS_BACKGROUND)
2033 if (r_glsl_permutation->tex_Texture_Refraction >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Refraction , waterplane->rt_refraction ? waterplane->rt_refraction->colortexture[0] : r_texture_black);
2034 if (r_glsl_permutation->tex_Texture_First >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , waterplane->rt_camera ? waterplane->rt_camera->colortexture[0] : r_texture_black);
2035 if (r_glsl_permutation->tex_Texture_Reflection >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
2039 if (r_glsl_permutation->tex_Texture_Reflection >= 0 && waterplane) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
2041 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap , r_shadow_prepassgeometrynormalmaptexture );
2042 if (r_glsl_permutation->tex_Texture_ScreenDiffuse >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse , r_shadow_prepasslightingdiffusetexture );
2043 if (r_glsl_permutation->tex_Texture_ScreenSpecular >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular , r_shadow_prepasslightingspeculartexture );
2044 if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
2046 if (r_glsl_permutation->tex_Texture_ShadowMap2D >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture );
2047 if (rsurface.rtlight)
2049 if (r_glsl_permutation->tex_Texture_Cube >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube , rsurface.rtlight->currentcubemap );
2050 if (r_glsl_permutation->tex_Texture_CubeProjection >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection , r_shadow_shadowmapvsdcttexture );
2053 if (r_glsl_permutation->tex_Texture_BounceGrid >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
2059 void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
2061 // select a permutation of the lighting shader appropriate to this
2062 // combination of texture, entity, light source, and fogging, only use the
2063 // minimum features necessary to avoid wasting rendering time in the
2064 // fragment shader on features that are not being used
2065 dpuint64 permutation = 0;
2066 unsigned int mode = 0;
2067 const float *lightcolorbase = rtlight->currentcolor;
2068 float ambientscale = rtlight->ambientscale;
2069 float diffusescale = rtlight->diffusescale;
2070 float specularscale = rtlight->specularscale;
2071 // this is the location of the light in view space
2072 vec3_t viewlightorigin;
2073 // this transforms from view space (camera) to light space (cubemap)
2074 matrix4x4_t viewtolight;
2075 matrix4x4_t lighttoview;
2076 float viewtolight16f[16];
2078 mode = SHADERMODE_DEFERREDLIGHTSOURCE;
2079 if (rtlight->currentcubemap != r_texture_whitecube)
2080 permutation |= SHADERPERMUTATION_CUBEFILTER;
2081 if (diffusescale > 0)
2082 permutation |= SHADERPERMUTATION_DIFFUSE;
2083 if (specularscale > 0 && r_shadow_gloss.integer > 0)
2084 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2085 if (r_shadow_usingshadowmap2d)
2087 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
2088 if (r_shadow_shadowmapvsdct)
2089 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
2091 if (r_shadow_shadowmap2ddepthbuffer)
2092 permutation |= SHADERPERMUTATION_DEPTHRGB;
2094 if (vid.allowalphatocoverage)
2095 GL_AlphaToCoverage(false);
2096 Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
2097 Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
2098 Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
2099 Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
2100 switch(vid.renderpath)
2102 case RENDERPATH_GL20:
2103 case RENDERPATH_GLES2:
2104 R_SetupShader_SetPermutationGLSL(mode, permutation);
2105 if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f( r_glsl_permutation->loc_LightPosition , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
2106 if (r_glsl_permutation->loc_ViewToLight >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight , 1, false, viewtolight16f);
2107 if (r_glsl_permutation->loc_DeferredColor_Ambient >= 0) qglUniform3f( r_glsl_permutation->loc_DeferredColor_Ambient , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
2108 if (r_glsl_permutation->loc_DeferredColor_Diffuse >= 0) qglUniform3f( r_glsl_permutation->loc_DeferredColor_Diffuse , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
2109 if (r_glsl_permutation->loc_DeferredColor_Specular >= 0) qglUniform3f( r_glsl_permutation->loc_DeferredColor_Specular , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
2110 if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f( r_glsl_permutation->loc_ShadowMap_TextureScale , r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
2111 if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f( r_glsl_permutation->loc_ShadowMap_Parameters , r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
2112 if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f( r_glsl_permutation->loc_SpecularPower , (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
2113 if (r_glsl_permutation->loc_ScreenToDepth >= 0) qglUniform2f( r_glsl_permutation->loc_ScreenToDepth , r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
2114 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f( r_glsl_permutation->loc_PixelToScreenTexCoord , 1.0f/vid.width, 1.0f/vid.height);
2116 if (r_glsl_permutation->tex_Texture_Attenuation >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation , r_shadow_attenuationgradienttexture );
2117 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap , r_shadow_prepassgeometrynormalmaptexture );
2118 if (r_glsl_permutation->tex_Texture_Cube >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube , rsurface.rtlight->currentcubemap );
2119 if (r_glsl_permutation->tex_Texture_ShadowMap2D >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D , r_shadow_shadowmap2ddepthtexture );
2120 if (r_glsl_permutation->tex_Texture_CubeProjection >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection , r_shadow_shadowmapvsdcttexture );
2125 #define SKINFRAME_HASH 1024
2129 unsigned int loadsequence; // incremented each level change
2130 memexpandablearray_t array;
2131 skinframe_t *hash[SKINFRAME_HASH];
2134 r_skinframe_t r_skinframe;
2136 void R_SkinFrame_PrepareForPurge(void)
2138 r_skinframe.loadsequence++;
2139 // wrap it without hitting zero
2140 if (r_skinframe.loadsequence >= 200)
2141 r_skinframe.loadsequence = 1;
2144 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
2148 // mark the skinframe as used for the purging code
2149 skinframe->loadsequence = r_skinframe.loadsequence;
2152 void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
2156 if (s->merged == s->base)
2158 R_PurgeTexture(s->stain); s->stain = NULL;
2159 R_PurgeTexture(s->merged); s->merged = NULL;
2160 R_PurgeTexture(s->base); s->base = NULL;
2161 R_PurgeTexture(s->pants); s->pants = NULL;
2162 R_PurgeTexture(s->shirt); s->shirt = NULL;
2163 R_PurgeTexture(s->nmap); s->nmap = NULL;
2164 R_PurgeTexture(s->gloss); s->gloss = NULL;
2165 R_PurgeTexture(s->glow); s->glow = NULL;
2166 R_PurgeTexture(s->fog); s->fog = NULL;
2167 R_PurgeTexture(s->reflect); s->reflect = NULL;
2168 s->loadsequence = 0;
2171 void R_SkinFrame_Purge(void)
2175 for (i = 0;i < SKINFRAME_HASH;i++)
2177 for (s = r_skinframe.hash[i];s;s = s->next)
2179 if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
2180 R_SkinFrame_PurgeSkinFrame(s);
2185 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
2187 char basename[MAX_QPATH];
2189 Image_StripImageExtension(name, basename, sizeof(basename));
2191 if( last == NULL ) {
2193 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2194 item = r_skinframe.hash[hashindex];
2199 // linearly search through the hash bucket
2200 for( ; item ; item = item->next ) {
2201 if( !strcmp( item->basename, basename ) ) {
2208 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add)
2212 char basename[MAX_QPATH];
2214 Image_StripImageExtension(name, basename, sizeof(basename));
2216 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2217 for (item = r_skinframe.hash[hashindex];item;item = item->next)
2218 if (!strcmp(item->basename, basename) && (comparecrc < 0 || (item->textureflags == textureflags && item->comparewidth == comparewidth && item->compareheight == compareheight && item->comparecrc == comparecrc)))
2225 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
2226 memset(item, 0, sizeof(*item));
2227 strlcpy(item->basename, basename, sizeof(item->basename));
2228 item->textureflags = textureflags & ~TEXF_FORCE_RELOAD;
2229 item->comparewidth = comparewidth;
2230 item->compareheight = compareheight;
2231 item->comparecrc = comparecrc;
2232 item->next = r_skinframe.hash[hashindex];
2233 r_skinframe.hash[hashindex] = item;
2235 else if (textureflags & TEXF_FORCE_RELOAD)
2239 R_SkinFrame_PurgeSkinFrame(item);
2242 R_SkinFrame_MarkUsed(item);
2246 #define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
2248 unsigned long long avgcolor[5], wsum; \
2256 for(pix = 0; pix < cnt; ++pix) \
2259 for(comp = 0; comp < 3; ++comp) \
2261 if(w) /* ignore perfectly black pixels because that is better for model skins */ \
2264 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2266 for(comp = 0; comp < 3; ++comp) \
2267 avgcolor[comp] += getpixel * w; \
2270 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2271 avgcolor[4] += getpixel; \
2273 if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
2275 skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
2276 skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
2277 skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
2278 skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
2281 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2283 skinframe_t *skinframe;
2285 if (cls.state == ca_dedicated)
2288 // return an existing skinframe if already loaded
2289 // if loading of the first image fails, don't make a new skinframe as it
2290 // would cause all future lookups of this to be missing
2291 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, -1, false);
2292 if (skinframe && skinframe->base)
2295 return R_SkinFrame_LoadExternal_SkinFrame(skinframe, name, textureflags, complain, fallbacknotexture);
2298 extern cvar_t gl_picmip;
2299 skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2302 unsigned char *pixels;
2303 unsigned char *bumppixels;
2304 unsigned char *basepixels = NULL;
2305 int basepixels_width = 0;
2306 int basepixels_height = 0;
2307 rtexture_t *ddsbase = NULL;
2308 qboolean ddshasalpha = false;
2309 float ddsavgcolor[4];
2310 char basename[MAX_QPATH];
2311 int miplevel = R_PicmipForFlags(textureflags);
2312 int savemiplevel = miplevel;
2316 if (cls.state == ca_dedicated)
2319 Image_StripImageExtension(name, basename, sizeof(basename));
2321 // check for DDS texture file first
2322 if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2324 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2325 if (basepixels == NULL && fallbacknotexture)
2326 basepixels = Image_GenerateNoTexture();
2327 if (basepixels == NULL)
2331 // FIXME handle miplevel
2333 if (developer_loading.integer)
2334 Con_Printf("loading skin \"%s\"\n", name);
2336 // we've got some pixels to store, so really allocate this new texture now
2338 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2339 textureflags &= ~TEXF_FORCE_RELOAD;
2340 skinframe->stain = NULL;
2341 skinframe->merged = NULL;
2342 skinframe->base = NULL;
2343 skinframe->pants = NULL;
2344 skinframe->shirt = NULL;
2345 skinframe->nmap = NULL;
2346 skinframe->gloss = NULL;
2347 skinframe->glow = NULL;
2348 skinframe->fog = NULL;
2349 skinframe->reflect = NULL;
2350 skinframe->hasalpha = false;
2351 // we could store the q2animname here too
2355 skinframe->base = ddsbase;
2356 skinframe->hasalpha = ddshasalpha;
2357 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2358 if (r_loadfog && skinframe->hasalpha)
2359 skinframe->fog = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), false, textureflags | TEXF_ALPHA, NULL, NULL, miplevel, true);
2360 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2364 basepixels_width = image_width;
2365 basepixels_height = image_height;
2366 skinframe->base = R_LoadTexture2D (r_main_texturepool, skinframe->basename, basepixels_width, basepixels_height, basepixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL);
2367 if (textureflags & TEXF_ALPHA)
2369 for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2371 if (basepixels[j] < 255)
2373 skinframe->hasalpha = true;
2377 if (r_loadfog && skinframe->hasalpha)
2379 // has transparent pixels
2380 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2381 for (j = 0;j < image_width * image_height * 4;j += 4)
2386 pixels[j+3] = basepixels[j+3];
2388 skinframe->fog = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_mask", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL);
2392 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2394 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2395 if (r_savedds && qglGetCompressedTexImageARB && skinframe->base)
2396 R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2397 if (r_savedds && qglGetCompressedTexImageARB && skinframe->fog)
2398 R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2404 mymiplevel = savemiplevel;
2405 if (r_loadnormalmap)
2406 skinframe->nmap = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), false, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), NULL, NULL, mymiplevel, true);
2407 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2409 skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2410 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2411 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2412 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2415 // _norm is the name used by tenebrae and has been adopted as standard
2416 if (r_loadnormalmap && skinframe->nmap == NULL)
2418 mymiplevel = savemiplevel;
2419 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2421 skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2425 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2427 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2428 Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2429 skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2431 Mem_Free(bumppixels);
2433 else if (r_shadow_bumpscale_basetexture.value > 0)
2435 pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2436 Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2437 skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), basepixels_width, basepixels_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2441 if (r_savedds && qglGetCompressedTexImageARB && skinframe->nmap)
2442 R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2446 // _luma is supported only for tenebrae compatibility
2447 // _glow is the preferred name
2448 mymiplevel = savemiplevel;
2449 if (skinframe->glow == NULL && ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_luma", skinframe->basename), false, false, false, &mymiplevel))))
2451 skinframe->glow = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_glow.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2453 if (r_savedds && qglGetCompressedTexImageARB && skinframe->glow)
2454 R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2456 Mem_Free(pixels);pixels = NULL;
2459 mymiplevel = savemiplevel;
2460 if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2462 skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (gl_texturecompression_gloss.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2464 if (r_savedds && qglGetCompressedTexImageARB && skinframe->gloss)
2465 R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2471 mymiplevel = savemiplevel;
2472 if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2474 skinframe->pants = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2476 if (r_savedds && qglGetCompressedTexImageARB && skinframe->pants)
2477 R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2483 mymiplevel = savemiplevel;
2484 if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2486 skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2488 if (r_savedds && qglGetCompressedTexImageARB && skinframe->shirt)
2489 R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2495 mymiplevel = savemiplevel;
2496 if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2498 skinframe->reflect = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_reflectmask.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2500 if (r_savedds && qglGetCompressedTexImageARB && skinframe->reflect)
2501 R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2508 Mem_Free(basepixels);
2513 // this is only used by .spr32 sprites, HL .spr files, HL .bsp files
2514 skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, qboolean sRGB)
2517 skinframe_t *skinframe;
2520 if (cls.state == ca_dedicated)
2523 // if already loaded just return it, otherwise make a new skinframe
2524 skinframe = R_SkinFrame_Find(name, textureflags, width, height, (!(textureflags & TEXF_FORCE_RELOAD) && skindata) ? CRC_Block(skindata, width*height*4) : -1, true);
2525 if (skinframe->base)
2527 textureflags &= ~TEXF_FORCE_RELOAD;
2529 skinframe->stain = NULL;
2530 skinframe->merged = NULL;
2531 skinframe->base = NULL;
2532 skinframe->pants = NULL;
2533 skinframe->shirt = NULL;
2534 skinframe->nmap = NULL;
2535 skinframe->gloss = NULL;
2536 skinframe->glow = NULL;
2537 skinframe->fog = NULL;
2538 skinframe->reflect = NULL;
2539 skinframe->hasalpha = false;
2541 // if no data was provided, then clearly the caller wanted to get a blank skinframe
2545 if (developer_loading.integer)
2546 Con_Printf("loading 32bit skin \"%s\"\n", name);
2548 if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2550 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2551 unsigned char *b = a + width * height * 4;
2552 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2553 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, b, TEXTYPE_BGRA, (textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
2556 skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2557 if (textureflags & TEXF_ALPHA)
2559 for (i = 3;i < width * height * 4;i += 4)
2561 if (skindata[i] < 255)
2563 skinframe->hasalpha = true;
2567 if (r_loadfog && skinframe->hasalpha)
2569 unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2570 memcpy(fogpixels, skindata, width * height * 4);
2571 for (i = 0;i < width * height * 4;i += 4)
2572 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2573 skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2574 Mem_Free(fogpixels);
2578 R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2579 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2584 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2588 skinframe_t *skinframe;
2590 if (cls.state == ca_dedicated)
2593 // if already loaded just return it, otherwise make a new skinframe
2594 skinframe = R_SkinFrame_Find(name, textureflags, width, height, (!(textureflags & TEXF_FORCE_RELOAD) && skindata) ? CRC_Block(skindata, width*height) : -1, true);
2595 if (skinframe->base)
2597 //textureflags &= ~TEXF_FORCE_RELOAD;
2599 skinframe->stain = NULL;
2600 skinframe->merged = NULL;
2601 skinframe->base = NULL;
2602 skinframe->pants = NULL;
2603 skinframe->shirt = NULL;
2604 skinframe->nmap = NULL;
2605 skinframe->gloss = NULL;
2606 skinframe->glow = NULL;
2607 skinframe->fog = NULL;
2608 skinframe->reflect = NULL;
2609 skinframe->hasalpha = false;
2611 // if no data was provided, then clearly the caller wanted to get a blank skinframe
2615 if (developer_loading.integer)
2616 Con_Printf("loading quake skin \"%s\"\n", name);
2618 // we actually don't upload anything until the first use, because mdl skins frequently go unused, and are almost never used in both modes (colormapped and non-colormapped)
2619 skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2620 memcpy(skinframe->qpixels, skindata, width*height);
2621 skinframe->qwidth = width;
2622 skinframe->qheight = height;
2625 for (i = 0;i < width * height;i++)
2626 featuresmask |= palette_featureflags[skindata[i]];
2628 skinframe->hasalpha = false;
2631 skinframe->hasalpha = true;
2632 skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2633 skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2634 skinframe->qgeneratemerged = true;
2635 skinframe->qgeneratebase = skinframe->qhascolormapping;
2636 skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2638 R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2639 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2644 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboolean colormapped)
2648 unsigned char *skindata;
2651 if (!skinframe->qpixels)
2654 if (!skinframe->qhascolormapping)
2655 colormapped = false;
2659 if (!skinframe->qgeneratebase)
2664 if (!skinframe->qgeneratemerged)
2668 width = skinframe->qwidth;
2669 height = skinframe->qheight;
2670 skindata = skinframe->qpixels;
2672 if (skinframe->qgeneratenmap)
2674 unsigned char *a, *b;
2675 skinframe->qgeneratenmap = false;
2676 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2677 b = a + width * height * 4;
2678 // use either a custom palette or the quake palette
2679 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2680 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2681 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, b, TEXTYPE_BGRA, (skinframe->textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
2685 if (skinframe->qgenerateglow)
2687 skinframe->qgenerateglow = false;
2688 if (skinframe->hasalpha) // fence textures
2689 skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags | TEXF_ALPHA, -1, palette_bgra_onlyfullbrights_transparent); // glow
2691 skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_onlyfullbrights); // glow
2696 skinframe->qgeneratebase = false;
2697 skinframe->base = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nospecial", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nocolormapnofullbrights : palette_bgra_nocolormap);
2698 skinframe->pants = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_pantsaswhite);
2699 skinframe->shirt = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_shirtaswhite);
2703 skinframe->qgeneratemerged = false;
2704 if (skinframe->hasalpha) // fence textures
2705 skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags | TEXF_ALPHA, -1, skinframe->glow ? palette_bgra_nofullbrights_transparent : palette_bgra_transparent);
2707 skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nofullbrights : palette_bgra_complete);
2710 if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2712 Mem_Free(skinframe->qpixels);
2713 skinframe->qpixels = NULL;
2717 skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, const unsigned char *skindata, int width, int height, const unsigned int *palette, const unsigned int *alphapalette)
2720 skinframe_t *skinframe;
2723 if (cls.state == ca_dedicated)
2726 // if already loaded just return it, otherwise make a new skinframe
2727 skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2728 if (skinframe->base)
2730 textureflags &= ~TEXF_FORCE_RELOAD;
2732 skinframe->stain = NULL;
2733 skinframe->merged = NULL;
2734 skinframe->base = NULL;
2735 skinframe->pants = NULL;
2736 skinframe->shirt = NULL;
2737 skinframe->nmap = NULL;
2738 skinframe->gloss = NULL;
2739 skinframe->glow = NULL;
2740 skinframe->fog = NULL;
2741 skinframe->reflect = NULL;
2742 skinframe->hasalpha = false;
2744 // if no data was provided, then clearly the caller wanted to get a blank skinframe
2748 if (developer_loading.integer)
2749 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2751 skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2752 if ((textureflags & TEXF_ALPHA) && alphapalette)
2754 for (i = 0;i < width * height;i++)
2756 if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2758 skinframe->hasalpha = true;
2762 if (r_loadfog && skinframe->hasalpha)
2763 skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2766 R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2767 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2772 skinframe_t *R_SkinFrame_LoadMissing(void)
2774 skinframe_t *skinframe;
2776 if (cls.state == ca_dedicated)
2779 skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2780 skinframe->stain = NULL;
2781 skinframe->merged = NULL;
2782 skinframe->base = NULL;
2783 skinframe->pants = NULL;
2784 skinframe->shirt = NULL;
2785 skinframe->nmap = NULL;
2786 skinframe->gloss = NULL;
2787 skinframe->glow = NULL;
2788 skinframe->fog = NULL;
2789 skinframe->reflect = NULL;
2790 skinframe->hasalpha = false;
2792 skinframe->avgcolor[0] = rand() / RAND_MAX;
2793 skinframe->avgcolor[1] = rand() / RAND_MAX;
2794 skinframe->avgcolor[2] = rand() / RAND_MAX;
2795 skinframe->avgcolor[3] = 1;
2800 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2803 static unsigned char pix[16][16][4];
2805 if (cls.state == ca_dedicated)
2808 // this makes a light grey/dark grey checkerboard texture
2811 for (y = 0; y < 16; y++)
2813 for (x = 0; x < 16; x++)
2815 if ((y < 8) ^ (x < 8))
2833 return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, pix[0][0], 16, 16, false);
2836 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qboolean sRGB)
2838 skinframe_t *skinframe;
2839 if (cls.state == ca_dedicated)
2841 // if already loaded just return it, otherwise make a new skinframe
2842 skinframe = R_SkinFrame_Find(name, textureflags, width, height, (textureflags & TEXF_FORCE_RELOAD) ? -1 : 0, true);
2843 if (skinframe->base)
2845 textureflags &= ~TEXF_FORCE_RELOAD;
2846 skinframe->stain = NULL;
2847 skinframe->merged = NULL;
2848 skinframe->base = NULL;
2849 skinframe->pants = NULL;
2850 skinframe->shirt = NULL;
2851 skinframe->nmap = NULL;
2852 skinframe->gloss = NULL;
2853 skinframe->glow = NULL;
2854 skinframe->fog = NULL;
2855 skinframe->reflect = NULL;
2856 skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2857 // if no data was provided, then clearly the caller wanted to get a blank skinframe
2860 if (developer_loading.integer)
2861 Con_Printf("loading 32bit skin \"%s\"\n", name);
2862 skinframe->base = skinframe->merged = tex;
2863 Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2867 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2868 typedef struct suffixinfo_s
2871 qboolean flipx, flipy, flipdiagonal;
2874 static suffixinfo_t suffix[3][6] =
2877 {"px", false, false, false},
2878 {"nx", false, false, false},
2879 {"py", false, false, false},
2880 {"ny", false, false, false},
2881 {"pz", false, false, false},
2882 {"nz", false, false, false}
2885 {"posx", false, false, false},
2886 {"negx", false, false, false},
2887 {"posy", false, false, false},
2888 {"negy", false, false, false},
2889 {"posz", false, false, false},
2890 {"negz", false, false, false}
2893 {"rt", true, false, true},
2894 {"lf", false, true, true},
2895 {"ft", true, true, false},
2896 {"bk", false, false, false},
2897 {"up", true, false, true},
2898 {"dn", true, false, true}
2902 static int componentorder[4] = {0, 1, 2, 3};
2904 static rtexture_t *R_LoadCubemap(const char *basename)
2906 int i, j, cubemapsize;
2907 unsigned char *cubemappixels, *image_buffer;
2908 rtexture_t *cubemaptexture;
2910 // must start 0 so the first loadimagepixels has no requested width/height
2912 cubemappixels = NULL;
2913 cubemaptexture = NULL;
2914 // keep trying different suffix groups (posx, px, rt) until one loads
2915 for (j = 0;j < 3 && !cubemappixels;j++)
2917 // load the 6 images in the suffix group
2918 for (i = 0;i < 6;i++)
2920 // generate an image name based on the base and and suffix
2921 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2923 if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
2925 // an image loaded, make sure width and height are equal
2926 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
2928 // if this is the first image to load successfully, allocate the cubemap memory
2929 if (!cubemappixels && image_width >= 1)
2931 cubemapsize = image_width;
2932 // note this clears to black, so unavailable sides are black
2933 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2935 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2937 Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_buffer, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder);
2940 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2942 Mem_Free(image_buffer);
2946 // if a cubemap loaded, upload it
2949 if (developer_loading.integer)
2950 Con_Printf("loading cubemap \"%s\"\n", basename);
2952 cubemaptexture = R_LoadTextureCubeMap(r_main_texturepool, basename, cubemapsize, cubemappixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, (gl_texturecompression_lightcubemaps.integer && gl_texturecompression.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
2953 Mem_Free(cubemappixels);
2957 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
2958 if (developer_loading.integer)
2960 Con_Printf("(tried tried images ");
2961 for (j = 0;j < 3;j++)
2962 for (i = 0;i < 6;i++)
2963 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2964 Con_Print(" and was unable to find any of them).\n");
2967 return cubemaptexture;
2970 rtexture_t *R_GetCubemap(const char *basename)
2973 for (i = 0;i < r_texture_numcubemaps;i++)
2974 if (r_texture_cubemaps[i] != NULL)
2975 if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
2976 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
2977 if (i >= MAX_CUBEMAPS || !r_main_mempool)
2978 return r_texture_whitecube;
2979 r_texture_numcubemaps++;
2980 r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
2981 strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
2982 r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
2983 return r_texture_cubemaps[i]->texture;
2986 static void R_Main_FreeViewCache(void)
2988 if (r_refdef.viewcache.entityvisible)
2989 Mem_Free(r_refdef.viewcache.entityvisible);
2990 if (r_refdef.viewcache.world_pvsbits)
2991 Mem_Free(r_refdef.viewcache.world_pvsbits);
2992 if (r_refdef.viewcache.world_leafvisible)
2993 Mem_Free(r_refdef.viewcache.world_leafvisible);
2994 if (r_refdef.viewcache.world_surfacevisible)
2995 Mem_Free(r_refdef.viewcache.world_surfacevisible);
2996 memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
2999 static void R_Main_ResizeViewCache(void)
3001 int numentities = r_refdef.scene.numentities;
3002 int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
3003 int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
3004 int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
3005 int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
3006 if (r_refdef.viewcache.maxentities < numentities)
3008 r_refdef.viewcache.maxentities = numentities;
3009 if (r_refdef.viewcache.entityvisible)
3010 Mem_Free(r_refdef.viewcache.entityvisible);
3011 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
3013 if (r_refdef.viewcache.world_numclusters != numclusters)
3015 r_refdef.viewcache.world_numclusters = numclusters;
3016 r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
3017 if (r_refdef.viewcache.world_pvsbits)
3018 Mem_Free(r_refdef.viewcache.world_pvsbits);
3019 r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
3021 if (r_refdef.viewcache.world_numleafs != numleafs)
3023 r_refdef.viewcache.world_numleafs = numleafs;
3024 if (r_refdef.viewcache.world_leafvisible)
3025 Mem_Free(r_refdef.viewcache.world_leafvisible);
3026 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
3028 if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
3030 r_refdef.viewcache.world_numsurfaces = numsurfaces;
3031 if (r_refdef.viewcache.world_surfacevisible)
3032 Mem_Free(r_refdef.viewcache.world_surfacevisible);
3033 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
3037 extern rtexture_t *loadingscreentexture;
3038 static void gl_main_start(void)
3040 loadingscreentexture = NULL;
3041 r_texture_blanknormalmap = NULL;
3042 r_texture_white = NULL;
3043 r_texture_grey128 = NULL;
3044 r_texture_black = NULL;
3045 r_texture_whitecube = NULL;
3046 r_texture_normalizationcube = NULL;
3047 r_texture_fogattenuation = NULL;
3048 r_texture_fogheighttexture = NULL;
3049 r_texture_gammaramps = NULL;
3050 r_texture_numcubemaps = 0;
3051 r_uniformbufferalignment = 32;
3053 r_loaddds = r_texture_dds_load.integer != 0;
3054 r_savedds = vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3056 switch(vid.renderpath)
3058 case RENDERPATH_GL20:
3059 case RENDERPATH_GLES2:
3060 Cvar_SetValueQuick(&r_textureunits, vid.texunits);
3061 Cvar_SetValueQuick(&gl_combine, 1);
3062 Cvar_SetValueQuick(&r_glsl, 1);
3063 r_loadnormalmap = true;
3066 #ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
3067 if (vid.support.arb_uniform_buffer_object)
3068 qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
3074 R_FrameData_Reset();
3075 R_BufferData_Reset();
3079 memset(r_queries, 0, sizeof(r_queries));
3081 r_qwskincache = NULL;
3082 r_qwskincache_size = 0;
3084 // due to caching of texture_t references, the collision cache must be reset
3085 Collision_Cache_Reset(true);
3087 // set up r_skinframe loading system for textures
3088 memset(&r_skinframe, 0, sizeof(r_skinframe));
3089 r_skinframe.loadsequence = 1;
3090 Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
3092 r_main_texturepool = R_AllocTexturePool();
3093 R_BuildBlankTextures();
3095 if (vid.support.arb_texture_cube_map)
3098 R_BuildNormalizationCube();
3100 r_texture_fogattenuation = NULL;
3101 r_texture_fogheighttexture = NULL;
3102 r_texture_gammaramps = NULL;
3103 //r_texture_fogintensity = NULL;
3104 memset(&r_fb, 0, sizeof(r_fb));
3105 Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
3106 r_glsl_permutation = NULL;
3107 memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3108 Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
3109 memset(&r_svbsp, 0, sizeof (r_svbsp));
3111 memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
3112 r_texture_numcubemaps = 0;
3114 r_refdef.fogmasktable_density = 0;
3117 // For Steelstorm Android
3118 // FIXME CACHE the program and reload
3119 // FIXME see possible combinations for SS:BR android
3120 Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
3121 R_SetupShader_SetPermutationGLSL(0, 12);
3122 R_SetupShader_SetPermutationGLSL(0, 13);
3123 R_SetupShader_SetPermutationGLSL(0, 8388621);
3124 R_SetupShader_SetPermutationGLSL(3, 0);
3125 R_SetupShader_SetPermutationGLSL(3, 2048);
3126 R_SetupShader_SetPermutationGLSL(5, 0);
3127 R_SetupShader_SetPermutationGLSL(5, 2);
3128 R_SetupShader_SetPermutationGLSL(5, 2048);
3129 R_SetupShader_SetPermutationGLSL(5, 8388608);
3130 R_SetupShader_SetPermutationGLSL(11, 1);
3131 R_SetupShader_SetPermutationGLSL(11, 2049);
3132 R_SetupShader_SetPermutationGLSL(11, 8193);
3133 R_SetupShader_SetPermutationGLSL(11, 10241);
3134 Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
3138 static void gl_main_shutdown(void)
3140 R_RenderTarget_FreeUnused(true);
3141 Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
3143 R_FrameData_Reset();
3144 R_BufferData_Reset();
3146 R_Main_FreeViewCache();
3148 switch(vid.renderpath)
3150 case RENDERPATH_GL20:
3151 case RENDERPATH_GLES2:
3152 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
3154 qglDeleteQueriesARB(r_maxqueries, r_queries);
3161 memset(r_queries, 0, sizeof(r_queries));
3163 r_qwskincache = NULL;
3164 r_qwskincache_size = 0;
3166 // clear out the r_skinframe state
3167 Mem_ExpandableArray_FreeArray(&r_skinframe.array);
3168 memset(&r_skinframe, 0, sizeof(r_skinframe));
3171 Mem_Free(r_svbsp.nodes);
3172 memset(&r_svbsp, 0, sizeof (r_svbsp));
3173 R_FreeTexturePool(&r_main_texturepool);
3174 loadingscreentexture = NULL;
3175 r_texture_blanknormalmap = NULL;
3176 r_texture_white = NULL;
3177 r_texture_grey128 = NULL;
3178 r_texture_black = NULL;
3179 r_texture_whitecube = NULL;
3180 r_texture_normalizationcube = NULL;
3181 r_texture_fogattenuation = NULL;
3182 r_texture_fogheighttexture = NULL;
3183 r_texture_gammaramps = NULL;
3184 r_texture_numcubemaps = 0;
3185 //r_texture_fogintensity = NULL;
3186 memset(&r_fb, 0, sizeof(r_fb));
3189 r_glsl_permutation = NULL;
3190 memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3191 Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
3194 static void gl_main_newmap(void)
3196 // FIXME: move this code to client
3197 char *entities, entname[MAX_QPATH];
3199 Mem_Free(r_qwskincache);
3200 r_qwskincache = NULL;
3201 r_qwskincache_size = 0;
3204 dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension);
3205 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
3207 CL_ParseEntityLump(entities);
3211 if (cl.worldmodel->brush.entities)
3212 CL_ParseEntityLump(cl.worldmodel->brush.entities);
3214 R_Main_FreeViewCache();
3216 R_FrameData_Reset();
3217 R_BufferData_Reset();
3220 void GL_Main_Init(void)
3223 r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
3224 R_InitShaderModeInfo();
3226 Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
3227 Cmd_AddCommand("r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
3228 // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
3229 if (gamemode == GAME_NEHAHRA)
3231 Cvar_RegisterVariable (&gl_fogenable);
3232 Cvar_RegisterVariable (&gl_fogdensity);
3233 Cvar_RegisterVariable (&gl_fogred);
3234 Cvar_RegisterVariable (&gl_foggreen);
3235 Cvar_RegisterVariable (&gl_fogblue);
3236 Cvar_RegisterVariable (&gl_fogstart);
3237 Cvar_RegisterVariable (&gl_fogend);
3238 Cvar_RegisterVariable (&gl_skyclip);
3240 Cvar_RegisterVariable(&r_motionblur);
3241 Cvar_RegisterVariable(&r_damageblur);
3242 Cvar_RegisterVariable(&r_motionblur_averaging);
3243 Cvar_RegisterVariable(&r_motionblur_randomize);
3244 Cvar_RegisterVariable(&r_motionblur_minblur);
3245 Cvar_RegisterVariable(&r_motionblur_maxblur);
3246 Cvar_RegisterVariable(&r_motionblur_velocityfactor);
3247 Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed);
3248 Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed);
3249 Cvar_RegisterVariable(&r_motionblur_mousefactor);
3250 Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed);
3251 Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed);
3252 Cvar_RegisterVariable(&r_equalize_entities_fullbright);
3253 Cvar_RegisterVariable(&r_equalize_entities_minambient);
3254 Cvar_RegisterVariable(&r_equalize_entities_by);
3255 Cvar_RegisterVariable(&r_equalize_entities_to);
3256 Cvar_RegisterVariable(&r_depthfirst);
3257 Cvar_RegisterVariable(&r_useinfinitefarclip);
3258 Cvar_RegisterVariable(&r_farclip_base);
3259 Cvar_RegisterVariable(&r_farclip_world);
3260 Cvar_RegisterVariable(&r_nearclip);
3261 Cvar_RegisterVariable(&r_deformvertexes);
3262 Cvar_RegisterVariable(&r_transparent);
3263 Cvar_RegisterVariable(&r_transparent_alphatocoverage);
3264 Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
3265 Cvar_RegisterVariable(&r_transparent_useplanardistance);
3266 Cvar_RegisterVariable(&r_showoverdraw);
3267 Cvar_RegisterVariable(&r_showbboxes);
3268 Cvar_RegisterVariable(&r_showbboxes_client);
3269 Cvar_RegisterVariable(&r_showsurfaces);
3270 Cvar_RegisterVariable(&r_showtris);
3271 Cvar_RegisterVariable(&r_shownormals);
3272 Cvar_RegisterVariable(&r_showlighting);
3273 Cvar_RegisterVariable(&r_showshadowvolumes);
3274 Cvar_RegisterVariable(&r_showcollisionbrushes);
3275 Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
3276 Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
3277 Cvar_RegisterVariable(&r_showdisabledepthtest);
3278 Cvar_RegisterVariable(&r_showspriteedges);
3279 Cvar_RegisterVariable(&r_showparticleedges);
3280 Cvar_RegisterVariable(&r_drawportals);
3281 Cvar_RegisterVariable(&r_drawentities);
3282 Cvar_RegisterVariable(&r_draw2d);
3283 Cvar_RegisterVariable(&r_drawworld);
3284 Cvar_RegisterVariable(&r_cullentities_trace);
3285 Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
3286 Cvar_RegisterVariable(&r_cullentities_trace_samples);
3287 Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
3288 Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
3289 Cvar_RegisterVariable(&r_cullentities_trace_expand);
3290 Cvar_RegisterVariable(&r_cullentities_trace_pad);
3291 Cvar_RegisterVariable(&r_cullentities_trace_delay);
3292 Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
3293 Cvar_RegisterVariable(&r_sortentities);
3294 Cvar_RegisterVariable(&r_drawviewmodel);
3295 Cvar_RegisterVariable(&r_drawexteriormodel);
3296 Cvar_RegisterVariable(&r_speeds);
3297 Cvar_RegisterVariable(&r_fullbrights);
3298 Cvar_RegisterVariable(&r_wateralpha);
3299 Cvar_RegisterVariable(&r_dynamic);
3300 Cvar_RegisterVariable(&r_fakelight);
3301 Cvar_RegisterVariable(&r_fakelight_intensity);
3302 Cvar_RegisterVariable(&r_fullbright_directed);
3303 Cvar_RegisterVariable(&r_fullbright_directed_ambient);
3304 Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
3305 Cvar_RegisterVariable(&r_fullbright_directed_pitch);
3306 Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
3307 Cvar_RegisterVariable(&r_fullbright);
3308 Cvar_RegisterVariable(&r_shadows);
3309 Cvar_RegisterVariable(&r_shadows_darken);
3310 Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
3311 Cvar_RegisterVariable(&r_shadows_castfrombmodels);
3312 Cvar_RegisterVariable(&r_shadows_throwdistance);
3313 Cvar_RegisterVariable(&r_shadows_throwdirection);
3314 Cvar_RegisterVariable(&r_shadows_focus);
3315 Cvar_RegisterVariable(&r_shadows_shadowmapscale);
3316 Cvar_RegisterVariable(&r_shadows_shadowmapbias);
3317 Cvar_RegisterVariable(&r_q1bsp_skymasking);
3318 Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
3319 Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
3320 Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
3321 Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
3322 Cvar_RegisterVariable(&r_fog_exp2);
3323 Cvar_RegisterVariable(&r_fog_clear);
3324 Cvar_RegisterVariable(&r_drawfog);
3325 Cvar_RegisterVariable(&r_transparentdepthmasking);
3326 Cvar_RegisterVariable(&r_transparent_sortmindist);
3327 Cvar_RegisterVariable(&r_transparent_sortmaxdist);
3328 Cvar_RegisterVariable(&r_transparent_sortarraysize);
3329 Cvar_RegisterVariable(&r_texture_dds_load);
3330 Cvar_RegisterVariable(&r_texture_dds_save);
3331 Cvar_RegisterVariable(&r_textureunits);
3332 Cvar_RegisterVariable(&gl_combine);
3333 Cvar_RegisterVariable(&r_usedepthtextures);
3334 Cvar_RegisterVariable(&r_viewfbo);
3335 Cvar_RegisterVariable(&r_rendertarget_debug);
3336 Cvar_RegisterVariable(&r_viewscale);
3337 Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3338 Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3339 Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3340 Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3341 Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3342 Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3343 Cvar_RegisterVariable(&r_glsl);
3344 Cvar_RegisterVariable(&r_glsl_deluxemapping);
3345 Cvar_RegisterVariable(&r_glsl_offsetmapping);
3346 Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3347 Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3348 Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3349 Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3350 Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3351 Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3352 Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3353 Cvar_RegisterVariable(&r_glsl_postprocess);
3354 Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3355 Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3356 Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3357 Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3358 Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3359 Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3360 Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3361 Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3362 Cvar_RegisterVariable(&r_celshading);
3363 Cvar_RegisterVariable(&r_celoutlines);
3365 Cvar_RegisterVariable(&r_water);
3366 Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3367 Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3368 Cvar_RegisterVariable(&r_water_clippingplanebias);
3369 Cvar_RegisterVariable(&r_water_refractdistort);
3370 Cvar_RegisterVariable(&r_water_reflectdistort);
3371 Cvar_RegisterVariable(&r_water_scissormode);
3372 Cvar_RegisterVariable(&r_water_lowquality);
3373 Cvar_RegisterVariable(&r_water_hideplayer);
3375 Cvar_RegisterVariable(&r_lerpsprites);
3376 Cvar_RegisterVariable(&r_lerpmodels);
3377 Cvar_RegisterVariable(&r_lerplightstyles);
3378 Cvar_RegisterVariable(&r_waterscroll);
3379 Cvar_RegisterVariable(&r_bloom);
3380 Cvar_RegisterVariable(&r_bloom_colorscale);
3381 Cvar_RegisterVariable(&r_bloom_brighten);
3382 Cvar_RegisterVariable(&r_bloom_blur);
3383 Cvar_RegisterVariable(&r_bloom_resolution);
3384 Cvar_RegisterVariable(&r_bloom_colorexponent);
3385 Cvar_RegisterVariable(&r_bloom_colorsubtract);
3386 Cvar_RegisterVariable(&r_bloom_scenebrightness);
3387 Cvar_RegisterVariable(&r_hdr_scenebrightness);
3388 Cvar_RegisterVariable(&r_hdr_glowintensity);
3389 Cvar_RegisterVariable(&r_hdr_irisadaptation);
3390 Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3391 Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3392 Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3393 Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3394 Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3395 Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3396 Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3397 Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3398 Cvar_RegisterVariable(&developer_texturelogging);
3399 Cvar_RegisterVariable(&gl_lightmaps);
3400 Cvar_RegisterVariable(&r_test);
3401 Cvar_RegisterVariable(&r_batch_multidraw);
3402 Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3403 Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3404 Cvar_RegisterVariable(&r_glsl_skeletal);
3405 Cvar_RegisterVariable(&r_glsl_saturation);
3406 Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3407 Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3408 Cvar_RegisterVariable(&r_framedatasize);
3409 for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3410 Cvar_RegisterVariable(&r_buffermegs[i]);
3411 Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3412 if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3413 Cvar_SetValue("r_fullbrights", 0);
3414 #ifdef DP_MOBILETOUCH
3415 // GLES devices have terrible depth precision in general, so...
3416 Cvar_SetValueQuick(&r_nearclip, 4);
3417 Cvar_SetValueQuick(&r_farclip_base, 4096);
3418 Cvar_SetValueQuick(&r_farclip_world, 0);
3419 Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3421 R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3424 void Render_Init(void)
3437 R_LightningBeams_Init();
3447 extern char *ENGINE_EXTENSIONS;
3450 gl_renderer = (const char *)qglGetString(GL_RENDERER);
3451 gl_vendor = (const char *)qglGetString(GL_VENDOR);
3452 gl_version = (const char *)qglGetString(GL_VERSION);
3453 gl_extensions = (const char *)qglGetString(GL_EXTENSIONS);
3457 if (!gl_platformextensions)
3458 gl_platformextensions = "";
3460 Con_Printf("GL_VENDOR: %s\n", gl_vendor);
3461 Con_Printf("GL_RENDERER: %s\n", gl_renderer);
3462 Con_Printf("GL_VERSION: %s\n", gl_version);
3463 Con_DPrintf("GL_EXTENSIONS: %s\n", gl_extensions);
3464 Con_DPrintf("%s_EXTENSIONS: %s\n", gl_platform, gl_platformextensions);
3466 VID_CheckExtensions();
3468 // LordHavoc: report supported extensions
3470 Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions );
3472 Con_DPrintf("\nQuakeC extensions for server and client: %s\n", vm_sv_extensions );
3475 // clear to black (loading plaque will be seen over this)
3476 GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128);
3480 int R_CullBox(const vec3_t mins, const vec3_t maxs)
3484 if (r_trippy.integer)
3486 for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
3488 p = r_refdef.view.frustum + i;
3493 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3497 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3501 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3505 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3509 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3513 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3517 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3521 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3529 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3533 if (r_trippy.integer)
3535 for (i = 0;i < numplanes;i++)
3542 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3546 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3550 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3554 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3558 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3562 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3566 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3570 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3578 //==================================================================================
3580 // LordHavoc: this stores temporary data used within the same frame
3582 typedef struct r_framedata_mem_s
3584 struct r_framedata_mem_s *purge; // older mem block to free on next frame
3585 size_t size; // how much usable space
3586 size_t current; // how much space in use
3587 size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3588 size_t wantedsize; // how much space was allocated
3589 unsigned char *data; // start of real data (16byte aligned)
3593 static r_framedata_mem_t *r_framedata_mem;
3595 void R_FrameData_Reset(void)
3597 while (r_framedata_mem)
3599 r_framedata_mem_t *next = r_framedata_mem->purge;
3600 Mem_Free(r_framedata_mem);
3601 r_framedata_mem = next;
3605 static void R_FrameData_Resize(qboolean mustgrow)
3608 wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3609 wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3610 if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3612 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3613 newmem->wantedsize = wantedsize;
3614 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3615 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3616 newmem->current = 0;
3618 newmem->purge = r_framedata_mem;
3619 r_framedata_mem = newmem;
3623 void R_FrameData_NewFrame(void)
3625 R_FrameData_Resize(false);
3626 if (!r_framedata_mem)
3628 // if we ran out of space on the last frame, free the old memory now
3629 while (r_framedata_mem->purge)
3631 // repeatedly remove the second item in the list, leaving only head
3632 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3633 Mem_Free(r_framedata_mem->purge);
3634 r_framedata_mem->purge = next;
3636 // reset the current mem pointer
3637 r_framedata_mem->current = 0;
3638 r_framedata_mem->mark = 0;
3641 void *R_FrameData_Alloc(size_t size)
3646 // align to 16 byte boundary - the data pointer is already aligned, so we
3647 // only need to ensure the size of every allocation is also aligned
3648 size = (size + 15) & ~15;
3650 while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3652 // emergency - we ran out of space, allocate more memory
3653 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3654 newvalue = r_framedatasize.value * 2.0f;
3655 // upper bound based on architecture - if we try to allocate more than this we could overflow, better to loop until we error out on allocation failure
3656 if (sizeof(size_t) >= 8)
3657 newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3659 newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3660 // this might not be a growing it, but we'll allocate another buffer every time
3661 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3662 R_FrameData_Resize(true);
3665 data = r_framedata_mem->data + r_framedata_mem->current;
3666 r_framedata_mem->current += size;
3668 // count the usage for stats
3669 r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3670 r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3672 return (void *)data;
3675 void *R_FrameData_Store(size_t size, void *data)
3677 void *d = R_FrameData_Alloc(size);
3679 memcpy(d, data, size);
3683 void R_FrameData_SetMark(void)
3685 if (!r_framedata_mem)
3687 r_framedata_mem->mark = r_framedata_mem->current;
3690 void R_FrameData_ReturnToMark(void)
3692 if (!r_framedata_mem)
3694 r_framedata_mem->current = r_framedata_mem->mark;
3697 //==================================================================================
3699 // avoid reusing the same buffer objects on consecutive frames
3700 #define R_BUFFERDATA_CYCLE 3
3702 typedef struct r_bufferdata_buffer_s
3704 struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3705 size_t size; // how much usable space
3706 size_t current; // how much space in use
3707 r_meshbuffer_t *buffer; // the buffer itself
3709 r_bufferdata_buffer_t;
3711 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3712 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3714 /// frees all dynamic buffers
3715 void R_BufferData_Reset(void)
3718 r_bufferdata_buffer_t **p, *mem;
3719 for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3721 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3724 p = &r_bufferdata_buffer[cycle][type];
3730 R_Mesh_DestroyMeshBuffer(mem->buffer);
3737 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3738 static void R_BufferData_Resize(r_bufferdata_type_t type, qboolean mustgrow, size_t minsize)
3740 r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3742 float newvalue = r_buffermegs[type].value;
3744 // increase the cvar if we have to (but only if we already have a mem)
3745 if (mustgrow && mem)
3747 newvalue = bound(0.25f, newvalue, 256.0f);
3748 while (newvalue * 1024*1024 < minsize)
3751 // clamp the cvar to valid range
3752 newvalue = bound(0.25f, newvalue, 256.0f);
3753 if (r_buffermegs[type].value != newvalue)
3754 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3756 // calculate size in bytes
3757 size = (size_t)(newvalue * 1024*1024);
3758 size = bound(131072, size, 256*1024*1024);
3760 // allocate a new buffer if the size is different (purge old one later)
3761 // or if we were told we must grow the buffer
3762 if (!mem || mem->size != size || mustgrow)
3764 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3767 if (type == R_BUFFERDATA_VERTEX)
3768 mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3769 else if (type == R_BUFFERDATA_INDEX16)
3770 mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3771 else if (type == R_BUFFERDATA_INDEX32)
3772 mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3773 else if (type == R_BUFFERDATA_UNIFORM)
3774 mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3775 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3776 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3780 void R_BufferData_NewFrame(void)
3783 r_bufferdata_buffer_t **p, *mem;
3784 // cycle to the next frame's buffers
3785 r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3786 // if we ran out of space on the last time we used these buffers, free the old memory now
3787 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3789 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3791 R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3792 // free all but the head buffer, this is how we recycle obsolete
3793 // buffers after they are no longer in use
3794 p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3800 R_Mesh_DestroyMeshBuffer(mem->buffer);
3803 // reset the current offset
3804 r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3809 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3811 r_bufferdata_buffer_t *mem;
3815 *returnbufferoffset = 0;
3817 // align size to a byte boundary appropriate for the buffer type, this
3818 // makes all allocations have aligned start offsets
3819 if (type == R_BUFFERDATA_UNIFORM)
3820 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3822 padsize = (datasize + 15) & ~15;
3824 // if we ran out of space in this buffer we must allocate a new one
3825 if (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size)
3826 R_BufferData_Resize(type, true, padsize);
3828 // if the resize did not give us enough memory, fail
3829 if (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size)
3830 Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3832 mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3833 offset = (int)mem->current;
3834 mem->current += padsize;
3836 // upload the data to the buffer at the chosen offset
3838 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3839 R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3841 // count the usage for stats
3842 r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3843 r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3845 // return the buffer offset
3846 *returnbufferoffset = offset;
3851 //==================================================================================
3853 // LordHavoc: animcache originally written by Echon, rewritten since then
3856 * Animation cache prevents re-generating mesh data for an animated model
3857 * multiple times in one frame for lighting, shadowing, reflections, etc.
3860 void R_AnimCache_Free(void)
3864 void R_AnimCache_ClearCache(void)
3867 entity_render_t *ent;
3869 for (i = 0;i < r_refdef.scene.numentities;i++)
3871 ent = r_refdef.scene.entities[i];
3872 ent->animcache_vertex3f = NULL;
3873 ent->animcache_vertex3f_vertexbuffer = NULL;
3874 ent->animcache_vertex3f_bufferoffset = 0;
3875 ent->animcache_normal3f = NULL;
3876 ent->animcache_normal3f_vertexbuffer = NULL;
3877 ent->animcache_normal3f_bufferoffset = 0;
3878 ent->animcache_svector3f = NULL;
3879 ent->animcache_svector3f_vertexbuffer = NULL;
3880 ent->animcache_svector3f_bufferoffset = 0;
3881 ent->animcache_tvector3f = NULL;
3882 ent->animcache_tvector3f_vertexbuffer = NULL;
3883 ent->animcache_tvector3f_bufferoffset = 0;
3884 ent->animcache_vertexmesh = NULL;
3885 ent->animcache_vertexmesh_vertexbuffer = NULL;
3886 ent->animcache_vertexmesh_bufferoffset = 0;
3887 ent->animcache_skeletaltransform3x4 = NULL;
3888 ent->animcache_skeletaltransform3x4buffer = NULL;
3889 ent->animcache_skeletaltransform3x4offset = 0;
3890 ent->animcache_skeletaltransform3x4size = 0;
3894 static void R_AnimCache_UpdateEntityMeshBuffers(entity_render_t *ent, int numvertices)
3898 // check if we need the meshbuffers
3899 if (!vid.useinterleavedarrays)
3902 if (!ent->animcache_vertexmesh && ent->animcache_normal3f)
3903 ent->animcache_vertexmesh = (r_vertexmesh_t *)R_FrameData_Alloc(sizeof(r_vertexmesh_t)*numvertices);
3904 // TODO: upload vertexbuffer?
3905 if (ent->animcache_vertexmesh)
3907 r_refdef.stats[r_stat_animcache_vertexmesh_count] += 1;
3908 r_refdef.stats[r_stat_animcache_vertexmesh_vertices] += numvertices;
3909 r_refdef.stats[r_stat_animcache_vertexmesh_maxvertices] = max(r_refdef.stats[r_stat_animcache_vertexmesh_maxvertices], numvertices);
3910 memcpy(ent->animcache_vertexmesh, ent->model->surfmesh.data_vertexmesh, sizeof(r_vertexmesh_t)*numvertices);
3911 for (i = 0;i < numvertices;i++)
3912 memcpy(ent->animcache_vertexmesh[i].vertex3f, ent->animcache_vertex3f + 3*i, sizeof(float[3]));
3913 if (ent->animcache_svector3f)
3914 for (i = 0;i < numvertices;i++)
3915 memcpy(ent->animcache_vertexmesh[i].svector3f, ent->animcache_svector3f + 3*i, sizeof(float[3]));
3916 if (ent->animcache_tvector3f)
3917 for (i = 0;i < numvertices;i++)
3918 memcpy(ent->animcache_vertexmesh[i].tvector3f, ent->animcache_tvector3f + 3*i, sizeof(float[3]));
3919 if (ent->animcache_normal3f)
3920 for (i = 0;i < numvertices;i++)
3921 memcpy(ent->animcache_vertexmesh[i].normal3f, ent->animcache_normal3f + 3*i, sizeof(float[3]));
3925 qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
3927 dp_model_t *model = ent->model;
3930 // see if this ent is worth caching
3931 if (!model || !model->Draw || !model->AnimateVertices)
3933 // nothing to cache if it contains no animations and has no skeleton
3934 if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3936 // see if it is already cached for gpuskeletal
3937 if (ent->animcache_skeletaltransform3x4)
3939 // see if it is already cached as a mesh
3940 if (ent->animcache_vertex3f)
3942 // check if we need to add normals or tangents
3943 if (ent->animcache_normal3f)
3944 wantnormals = false;
3945 if (ent->animcache_svector3f)
3946 wanttangents = false;
3947 if (!wantnormals && !wanttangents)
3951 // check which kind of cache we need to generate
3952 if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3954 // cache the skeleton so the vertex shader can use it
3955 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3956 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3957 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3958 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3959 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4);
3960 // note: this can fail if the buffer is at the grow limit
3961 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3962 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3964 else if (ent->animcache_vertex3f)
3966 // mesh was already cached but we may need to add normals/tangents
3967 // (this only happens with multiple views, reflections, cameras, etc)
3968 if (wantnormals || wanttangents)
3970 numvertices = model->surfmesh.num_vertices;
3972 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3975 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3976 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3978 model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3979 R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices);
3980 r_refdef.stats[r_stat_animcache_shade_count] += 1;
3981 r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3982 r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3987 // generate mesh cache
3988 numvertices = model->surfmesh.num_vertices;
3989 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3991 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3994 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3995 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3997 model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
3998 R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices);
3999 if (wantnormals || wanttangents)
4001 r_refdef.stats[r_stat_animcache_shade_count] += 1;
4002 r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
4003 r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
4005 r_refdef.stats[r_stat_animcache_shape_count] += 1;
4006 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
4007 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
4012 void R_AnimCache_CacheVisibleEntities(void)
4016 // TODO: thread this
4017 // NOTE: R_PrepareRTLights() also caches entities
4019 for (i = 0;i < r_refdef.scene.numentities;i++)
4020 if (r_refdef.viewcache.entityvisible[i])
4021 R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
4024 //==================================================================================
4026 qboolean R_CanSeeBox(int numsamples, vec_t eyejitter, vec_t entboxenlarge, vec_t entboxexpand, vec_t pad, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs)
4029 vec3_t eyemins, eyemaxs;
4030 vec3_t boxmins, boxmaxs;
4031 vec3_t padmins, padmaxs;
4034 dp_model_t *model = r_refdef.scene.worldmodel;
4035 static vec3_t positions[] = {
4036 { 0.5f, 0.5f, 0.5f },
4037 { 0.0f, 0.0f, 0.0f },
4038 { 0.0f, 0.0f, 1.0f },
4039 { 0.0f, 1.0f, 0.0f },
4040 { 0.0f, 1.0f, 1.0f },
4041 { 1.0f, 0.0f, 0.0f },
4042 { 1.0f, 0.0f, 1.0f },
4043 { 1.0f, 1.0f, 0.0f },
4044 { 1.0f, 1.0f, 1.0f },
4047 // sample count can be set to -1 to skip this logic, for flicker-prone objects
4051 // view origin is not used for culling in portal/reflection/refraction renders or isometric views
4052 if (!r_refdef.view.usevieworiginculling)
4055 if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
4058 // expand the eye box a little
4059 eyemins[0] = eye[0] - eyejitter;
4060 eyemaxs[0] = eye[0] + eyejitter;
4061 eyemins[1] = eye[1] - eyejitter;
4062 eyemaxs[1] = eye[1] + eyejitter;
4063 eyemins[2] = eye[2] - eyejitter;
4064 eyemaxs[2] = eye[2] + eyejitter;
4065 // expand the box a little
4066 boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
4067 boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
4068 boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
4069 boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
4070 boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
4071 boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
4072 // make an even larger box for the acceptable area
4073 padmins[0] = boxmins[0] - pad;
4074 padmaxs[0] = boxmaxs[0] + pad;
4075 padmins[1] = boxmins[1] - pad;
4076 padmaxs[1] = boxmaxs[1] + pad;
4077 padmins[2] = boxmins[2] - pad;
4078 padmaxs[2] = boxmaxs[2] + pad;
4080 // return true if eye overlaps enlarged box
4081 if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
4084 // try specific positions in the box first - note that these can be cached
4085 if (r_cullentities_trace_entityocclusion.integer)
4087 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
4089 VectorCopy(eye, start);
4090 end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
4091 end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
4092 end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
4093 //trace_t trace = CL_TraceLine(start, end, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, 0.0f, true, false, NULL, true, true);
4094 trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
4095 // not picky - if the trace ended anywhere in the box we're good
4096 if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4100 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4103 // try various random positions
4104 for (i = 0; i < numsamples; i++)
4106 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
4107 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
4108 if (r_cullentities_trace_entityocclusion.integer)
4110 trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
4111 // not picky - if the trace ended anywhere in the box we're good
4112 if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4115 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4123 static void R_View_UpdateEntityVisible (void)
4128 entity_render_t *ent;
4130 if (r_refdef.envmap || r_fb.water.hideplayer)
4131 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
4132 else if (chase_active.integer || r_fb.water.renderingscene)
4133 renderimask = RENDER_VIEWMODEL;
4135 renderimask = RENDER_EXTERIORMODEL;
4136 if (!r_drawviewmodel.integer)
4137 renderimask |= RENDER_VIEWMODEL;
4138 if (!r_drawexteriormodel.integer)
4139 renderimask |= RENDER_EXTERIORMODEL;
4140 memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4141 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4143 // worldmodel can check visibility
4144 for (i = 0;i < r_refdef.scene.numentities;i++)
4146 ent = r_refdef.scene.entities[i];
4147 if (!(ent->flags & renderimask))
4148 if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
4149 if ((ent->flags & (RENDER_NODEPTHTEST | RENDER_WORLDOBJECT | RENDER_VIEWMODEL)) || r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, ent->mins, ent->maxs))
4150 r_refdef.viewcache.entityvisible[i] = true;
4155 // no worldmodel or it can't check visibility
4156 for (i = 0;i < r_refdef.scene.numentities;i++)
4158 ent = r_refdef.scene.entities[i];
4159 if (!(ent->flags & renderimask))
4160 if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
4161 r_refdef.viewcache.entityvisible[i] = true;
4164 if (r_cullentities_trace.integer)
4166 for (i = 0;i < r_refdef.scene.numentities;i++)
4168 if (!r_refdef.viewcache.entityvisible[i])
4170 ent = r_refdef.scene.entities[i];
4171 if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4173 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4174 if (R_CanSeeBox(samples, r_cullentities_trace_eyejitter.value, r_cullentities_trace_enlarge.value, r_cullentities_trace_expand.value, r_cullentities_trace_pad.value, r_refdef.view.origin, ent->mins, ent->maxs))
4175 ent->last_trace_visibility = realtime;
4176 if (ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
4177 r_refdef.viewcache.entityvisible[i] = 0;
4183 /// only used if skyrendermasked, and normally returns false
4184 static int R_DrawBrushModelsSky (void)
4187 entity_render_t *ent;
4190 for (i = 0;i < r_refdef.scene.numentities;i++)
4192 if (!r_refdef.viewcache.entityvisible[i])
4194 ent = r_refdef.scene.entities[i];
4195 if (!ent->model || !ent->model->DrawSky)
4197 ent->model->DrawSky(ent);
4203 static void R_DrawNoModel(entity_render_t *ent);
4204 static void R_DrawModels(void)
4207 entity_render_t *ent;
4209 for (i = 0;i < r_refdef.scene.numentities;i++)
4211 if (!r_refdef.viewcache.entityvisible[i])
4213 ent = r_refdef.scene.entities[i];
4214 r_refdef.stats[r_stat_entities]++;
4216 if (ent->model && !strncmp(ent->model->name, "models/proto_", 13))
4219 Matrix4x4_ToVectors(&ent->matrix, f, l, u, o);
4220 Con_Printf("R_DrawModels\n");
4221 Con_Printf("model %s O %f %f %f F %f %f %f L %f %f %f U %f %f %f\n", ent->model->name, o[0], o[1], o[2], f[0], f[1], f[2], l[0], l[1], l[2], u[0], u[1], u[2]);
4222 Con_Printf("group: %i %f %i %f %i %f %i %f\n", ent->framegroupblend[0].frame, ent->framegroupblend[0].lerp, ent->framegroupblend[1].frame, ent->framegroupblend[1].lerp, ent->framegroupblend[2].frame, ent->framegroupblend[2].lerp, ent->framegroupblend[3].frame, ent->framegroupblend[3].lerp);
4223 Con_Printf("blend: %i %f %i %f %i %f %i %f %i %f %i %f %i %f %i %f\n", ent->frameblend[0].subframe, ent->frameblend[0].lerp, ent->frameblend[1].subframe, ent->frameblend[1].lerp, ent->frameblend[2].subframe, ent->frameblend[2].lerp, ent->frameblend[3].subframe, ent->frameblend[3].lerp, ent->frameblend[4].subframe, ent->frameblend[4].lerp, ent->frameblend[5].subframe, ent->frameblend[5].lerp, ent->frameblend[6].subframe, ent->frameblend[6].lerp, ent->frameblend[7].subframe, ent->frameblend[7].lerp);
4226 if (ent->model && ent->model->Draw != NULL)
4227 ent->model->Draw(ent);
4233 static void R_DrawModelsDepth(void)
4236 entity_render_t *ent;
4238 for (i = 0;i < r_refdef.scene.numentities;i++)
4240 if (!r_refdef.viewcache.entityvisible[i])
4242 ent = r_refdef.scene.entities[i];
4243 if (ent->model && ent->model->DrawDepth != NULL)
4244 ent->model->DrawDepth(ent);
4248 static void R_DrawModelsDebug(void)
4251 entity_render_t *ent;
4253 for (i = 0;i < r_refdef.scene.numentities;i++)
4255 if (!r_refdef.viewcache.entityvisible[i])
4257 ent = r_refdef.scene.entities[i];
4258 if (ent->model && ent->model->DrawDebug != NULL)
4259 ent->model->DrawDebug(ent);
4263 static void R_DrawModelsAddWaterPlanes(void)
4266 entity_render_t *ent;
4268 for (i = 0;i < r_refdef.scene.numentities;i++)
4270 if (!r_refdef.viewcache.entityvisible[i])
4272 ent = r_refdef.scene.entities[i];
4273 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4274 ent->model->DrawAddWaterPlanes(ent);
4278 static float irisvecs[7][3] = {{0, 0, 0}, {-1, 0, 0}, {1, 0, 0}, {0, -1, 0}, {0, 1, 0}, {0, 0, -1}, {0, 0, 1}};
4280 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4282 if (r_hdr_irisadaptation.integer)
4287 vec3_t diffusenormal;
4289 vec_t brightness = 0.0f;
4294 VectorCopy(r_refdef.view.forward, forward);
4295 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4297 p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4298 p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4299 p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4300 R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4301 d = DotProduct(forward, diffusenormal);
4302 brightness += VectorLength(ambient);
4304 brightness += d * VectorLength(diffuse);
4306 brightness *= 1.0f / c;
4307 brightness += 0.00001f; // make sure it's never zero
4308 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4309 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4310 current = r_hdr_irisadaptation_value.value;
4312 current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4313 else if (current > goal)
4314 current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4315 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4316 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4318 else if (r_hdr_irisadaptation_value.value != 1.0f)
4319 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4322 static void R_View_SetFrustum(const int *scissor)
4325 double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4326 vec3_t forward, left, up, origin, v;
4330 // flipped x coordinates (because x points left here)
4331 fpx = 1.0 - 2.0 * (scissor[0] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4332 fnx = 1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4333 // non-flipped y coordinates
4334 fny = -1.0 + 2.0 * (scissor[1] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4335 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4338 // we can't trust r_refdef.view.forward and friends in reflected scenes
4339 Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4342 r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4343 r_refdef.view.frustum[0].normal[1] = 0 - 0;
4344 r_refdef.view.frustum[0].normal[2] = -1 - 0;
4345 r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4346 r_refdef.view.frustum[1].normal[1] = 0 + 0;
4347 r_refdef.view.frustum[1].normal[2] = -1 + 0;
4348 r_refdef.view.frustum[2].normal[0] = 0 - 0;
4349 r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4350 r_refdef.view.frustum[2].normal[2] = -1 - 0;
4351 r_refdef.view.frustum[3].normal[0] = 0 + 0;
4352 r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4353 r_refdef.view.frustum[3].normal[2] = -1 + 0;
4357 zNear = r_refdef.nearclip;
4358 nudge = 1.0 - 1.0 / (1<<23);
4359 r_refdef.view.frustum[4].normal[0] = 0 - 0;
4360 r_refdef.view.frustum[4].normal[1] = 0 - 0;
4361 r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4362 r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4363 r_refdef.view.frustum[5].normal[0] = 0 + 0;
4364 r_refdef.view.frustum[5].normal[1] = 0 + 0;
4365 r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4366 r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4372 r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4373 r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4374 r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4375 r_refdef.view.frustum[0].dist = m[15] - m[12];
4377 r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4378 r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4379 r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4380 r_refdef.view.frustum[1].dist = m[15] + m[12];
4382 r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4383 r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4384 r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4385 r_refdef.view.frustum[2].dist = m[15] - m[13];
4387 r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4388 r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4389 r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4390 r_refdef.view.frustum[3].dist = m[15] + m[13];
4392 r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4393 r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4394 r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4395 r_refdef.view.frustum[4].dist = m[15] - m[14];
4397 r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4398 r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4399 r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4400 r_refdef.view.frustum[5].dist = m[15] + m[14];
4403 if (r_refdef.view.useperspective)
4405 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4406 VectorMAMAM(1024, forward, fnx * 1024.0 * r_refdef.view.frustum_x, left, fny * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[0]);
4407 VectorMAMAM(1024, forward, fpx * 1024.0 * r_refdef.view.frustum_x, left, fny * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[1]);
4408 VectorMAMAM(1024, forward, fnx * 1024.0 * r_refdef.view.frustum_x, left, fpy * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[2]);
4409 VectorMAMAM(1024, forward, fpx * 1024.0 * r_refdef.view.frustum_x, left, fpy * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[3]);
4411 // then the normals from the corners relative to origin
4412 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4413 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4414 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4415 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4417 // in a NORMAL view, forward cross left == up
4418 // in a REFLECTED view, forward cross left == down
4419 // so our cross products above need to be adjusted for a left handed coordinate system
4420 CrossProduct(forward, left, v);
4421 if(DotProduct(v, up) < 0)
4423 VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4424 VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4425 VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4426 VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4429 // Leaving those out was a mistake, those were in the old code, and they
4430 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4431 // I couldn't reproduce it after adding those normalizations. --blub
4432 VectorNormalize(r_refdef.view.frustum[0].normal);
4433 VectorNormalize(r_refdef.view.frustum[1].normal);
4434 VectorNormalize(r_refdef.view.frustum[2].normal);
4435 VectorNormalize(r_refdef.view.frustum[3].normal);
4437 // make the corners absolute
4438 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4439 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4440 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4441 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4444 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4446 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4447 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4448 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4449 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4450 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4454 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4455 VectorScale(left, 1.0f, r_refdef.view.frustum[1].normal);
4456 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4457 VectorScale(up, 1.0f, r_refdef.view.frustum[3].normal);
4458 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4459 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4460 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4461 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4462 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4463 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4465 r_refdef.view.numfrustumplanes = 5;
4467 if (r_refdef.view.useclipplane)
4469 r_refdef.view.numfrustumplanes = 6;
4470 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4473 for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4474 PlaneClassify(r_refdef.view.frustum + i);
4476 // LordHavoc: note to all quake engine coders, Quake had a special case
4477 // for 90 degrees which assumed a square view (wrong), so I removed it,
4478 // Quake2 has it disabled as well.
4480 // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4481 //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4482 //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4483 //PlaneClassify(&frustum[0]);
4485 // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4486 //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4487 //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4488 //PlaneClassify(&frustum[1]);
4490 // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4491 //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4492 //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4493 //PlaneClassify(&frustum[2]);
4495 // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4496 //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4497 //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4498 //PlaneClassify(&frustum[3]);
4501 //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4502 //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4503 //PlaneClassify(&frustum[4]);
4506 static void R_View_UpdateWithScissor(const int *myscissor)
4508 R_Main_ResizeViewCache();
4509 R_View_SetFrustum(myscissor);
4510 R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4511 R_View_UpdateEntityVisible();
4514 static void R_View_Update(void)
4516 R_Main_ResizeViewCache();
4517 R_View_SetFrustum(NULL);
4518 R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4519 R_View_UpdateEntityVisible();
4522 float viewscalefpsadjusted = 1.0f;
4524 static void R_GetScaledViewSize(int width, int height, int *outwidth, int *outheight)
4526 float scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
4527 scale = bound(0.03125f, scale, 1.0f);
4528 *outwidth = (int)ceil(width * scale);
4529 *outheight = (int)ceil(height * scale);
4532 void R_SetupView(qboolean allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4534 const float *customclipplane = NULL;
4536 int /*rtwidth,*/ rtheight;
4537 if (r_refdef.view.useclipplane && allowwaterclippingplane)
4539 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4540 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4541 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4542 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4543 dist = r_refdef.view.clipplane.dist;
4544 plane[0] = r_refdef.view.clipplane.normal[0];
4545 plane[1] = r_refdef.view.clipplane.normal[1];
4546 plane[2] = r_refdef.view.clipplane.normal[2];
4548 customclipplane = plane;
4551 //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
4552 rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
4554 if (!r_refdef.view.useperspective)
4555 R_Viewport_InitOrtho3D(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane);
4556 else if (vid.stencil && r_useinfinitefarclip.integer)
4557 R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane);
4559 R_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane);
4560 R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4561 R_SetViewport(&r_refdef.view.viewport);
4564 void R_EntityMatrix(const matrix4x4_t *matrix)
4566 if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4568 gl_modelmatrixchanged = false;
4569 gl_modelmatrix = *matrix;
4570 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4571 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4572 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4573 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4575 switch(vid.renderpath)
4577 case RENDERPATH_GL20:
4578 case RENDERPATH_GLES2:
4579 if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4580 if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4586 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4588 r_viewport_t viewport;
4592 // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
4593 R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4594 R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4595 R_SetViewport(&viewport);
4596 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4597 GL_Color(1, 1, 1, 1);
4598 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4599 GL_BlendFunc(GL_ONE, GL_ZERO);
4600 GL_ScissorTest(false);
4601 GL_DepthMask(false);
4602 GL_DepthRange(0, 1);
4603 GL_DepthTest(false);
4604 GL_DepthFunc(GL_LEQUAL);
4605 R_EntityMatrix(&identitymatrix);
4606 R_Mesh_ResetTextureState();
4607 GL_PolygonOffset(0, 0);
4608 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
4609 switch(vid.renderpath)
4611 case RENDERPATH_GL20:
4612 case RENDERPATH_GLES2:
4613 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4616 GL_CullFace(GL_NONE);
4621 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4623 R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4626 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4628 R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4629 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4630 GL_Color(1, 1, 1, 1);
4631 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4632 GL_BlendFunc(GL_ONE, GL_ZERO);
4633 GL_ScissorTest(true);
4635 GL_DepthRange(0, 1);
4637 GL_DepthFunc(GL_LEQUAL);
4638 R_EntityMatrix(&identitymatrix);
4639 R_Mesh_ResetTextureState();
4640 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4641 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
4642 switch(vid.renderpath)
4644 case RENDERPATH_GL20:
4645 case RENDERPATH_GLES2:
4646 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4649 GL_CullFace(r_refdef.view.cullface_back);
4654 R_RenderView_UpdateViewVectors
4657 void R_RenderView_UpdateViewVectors(void)
4659 // break apart the view matrix into vectors for various purposes
4660 // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4661 // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4662 Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4663 VectorNegate(r_refdef.view.left, r_refdef.view.right);
4664 // make an inverted copy of the view matrix for tracking sprites
4665 Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4668 void R_RenderTarget_FreeUnused(qboolean force)
4671 end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
4672 for (i = 0; i < end; i++)
4674 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4675 // free resources for rendertargets that have not been used for a while
4676 // (note: this check is run after the frame render, so any targets used
4677 // this frame will not be affected even at low framerates)
4678 if (r && (realtime - r->lastusetime > 0.2 || force))
4681 R_Mesh_DestroyFramebufferObject(r->fbo);
4682 for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4683 if (r->colortexture[j])
4684 R_FreeTexture(r->colortexture[j]);
4685 if (r->depthtexture)
4686 R_FreeTexture(r->depthtexture);
4687 Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4692 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4694 float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4698 y2 = (th - y - h) * ih;
4709 r_rendertarget_t *R_RenderTarget_Get(int texturewidth, int textureheight, textype_t depthtextype, qboolean depthisrenderbuffer, textype_t colortextype0, textype_t colortextype1, textype_t colortextype2, textype_t colortextype3)
4712 r_rendertarget_t *r = NULL;
4714 // first try to reuse an existing slot if possible
4715 end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
4716 for (i = 0; i < end; i++)
4718 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4719 if (r && r->lastusetime != realtime && r->texturewidth == texturewidth && r->textureheight == textureheight && r->depthtextype == depthtextype && r->colortextype[0] == colortextype0 && r->colortextype[1] == colortextype1 && r->colortextype[2] == colortextype2 && r->colortextype[3] == colortextype3)
4724 // no unused exact match found, so we have to make one in the first unused slot
4725 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4726 r->texturewidth = texturewidth;
4727 r->textureheight = textureheight;
4728 r->colortextype[0] = colortextype0;
4729 r->colortextype[1] = colortextype1;
4730 r->colortextype[2] = colortextype2;
4731 r->colortextype[3] = colortextype3;
4732 r->depthtextype = depthtextype;
4733 r->depthisrenderbuffer = depthisrenderbuffer;
4734 for (j = 0; j < 4; j++)
4735 if (r->colortextype[j])
4736 r->colortexture[j] = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "rendertarget%i_%i_type%i", i, j, (int)r->colortextype[j]), r->texturewidth, r->textureheight, NULL, r->colortextype[j], TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
4737 if (r->depthtextype)
4739 if (r->depthisrenderbuffer)
4740 r->depthtexture = R_LoadTextureRenderBuffer(r_main_texturepool, va(vabuf, sizeof(vabuf), "renderbuffer%i_depth_type%i", i, (int)r->depthtextype), r->texturewidth, r->textureheight, r->depthtextype);
4742 r->depthtexture = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "rendertarget%i_depth_type%i", i, j, (int)r->depthtextype), r->texturewidth, r->textureheight, NULL, r->depthtextype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
4744 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4746 r_refdef.stats[r_stat_rendertargets_used]++;
4747 r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4748 r->lastusetime = realtime;
4749 R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4753 static void R_Water_StartFrame(void)
4755 int waterwidth, waterheight;
4757 if (vid.width > (int)vid.maxtexturesize_2d || vid.height > (int)vid.maxtexturesize_2d)
4760 // set waterwidth and waterheight to the water resolution that will be
4761 // used (often less than the screen resolution for faster rendering)
4762 waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width);
4763 waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height);
4764 R_GetScaledViewSize(waterwidth, waterheight, &waterwidth, &waterheight);
4766 if (!r_water.integer || r_showsurfaces.integer)
4767 waterwidth = waterheight = 0;
4769 // set up variables that will be used in shader setup
4770 r_fb.water.waterwidth = waterwidth;
4771 r_fb.water.waterheight = waterheight;
4772 r_fb.water.texturewidth = waterwidth;
4773 r_fb.water.textureheight = waterheight;
4774 r_fb.water.camerawidth = waterwidth;
4775 r_fb.water.cameraheight = waterheight;
4776 r_fb.water.screenscale[0] = 0.5f;
4777 r_fb.water.screenscale[1] = 0.5f;
4778 r_fb.water.screencenter[0] = 0.5f;
4779 r_fb.water.screencenter[1] = 0.5f;
4780 r_fb.water.enabled = waterwidth != 0;
4782 r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4783 r_fb.water.numwaterplanes = 0;
4786 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4788 int planeindex, bestplaneindex, vertexindex;
4789 vec3_t mins, maxs, normal, center, v, n;
4790 vec_t planescore, bestplanescore;
4792 r_waterstate_waterplane_t *p;
4793 texture_t *t = R_GetCurrentTexture(surface->texture);
4795 rsurface.texture = t;
4796 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4797 // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4798 if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4800 // average the vertex normals, find the surface bounds (after deformvertexes)
4801 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4802 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4803 VectorCopy(n, normal);
4804 VectorCopy(v, mins);
4805 VectorCopy(v, maxs);
4806 for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4808 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4809 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4810 VectorAdd(normal, n, normal);
4811 mins[0] = min(mins[0], v[0]);
4812 mins[1] = min(mins[1], v[1]);
4813 mins[2] = min(mins[2], v[2]);
4814 maxs[0] = max(maxs[0], v[0]);
4815 maxs[1] = max(maxs[1], v[1]);
4816 maxs[2] = max(maxs[2], v[2]);
4818 VectorNormalize(normal);
4819 VectorMAM(0.5f, mins, 0.5f, maxs, center);
4821 VectorCopy(normal, plane.normal);
4822 VectorNormalize(plane.normal);
4823 plane.dist = DotProduct(center, plane.normal);
4824 PlaneClassify(&plane);
4825 if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4827 // skip backfaces (except if nocullface is set)
4828 // if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4830 VectorNegate(plane.normal, plane.normal);
4832 PlaneClassify(&plane);
4836 // find a matching plane if there is one
4837 bestplaneindex = -1;
4838 bestplanescore = 1048576.0f;
4839 for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4841 if(p->camera_entity == t->camera_entity)
4843 planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4844 if (bestplaneindex < 0 || bestplanescore > planescore)
4846 bestplaneindex = planeindex;
4847 bestplanescore = planescore;
4851 planeindex = bestplaneindex;
4853 // if this surface does not fit any known plane rendered this frame, add one
4854 if (planeindex < 0 || bestplanescore > 0.001f)
4856 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4858 // store the new plane
4859 planeindex = r_fb.water.numwaterplanes++;
4860 p = r_fb.water.waterplanes + planeindex;
4862 // clear materialflags and pvs
4863 p->materialflags = 0;
4864 p->pvsvalid = false;
4865 p->camera_entity = t->camera_entity;
4866 VectorCopy(mins, p->mins);
4867 VectorCopy(maxs, p->maxs);
4871 // We're totally screwed.
4877 // merge mins/maxs when we're adding this surface to the plane
4878 p = r_fb.water.waterplanes + planeindex;
4879 p->mins[0] = min(p->mins[0], mins[0]);
4880 p->mins[1] = min(p->mins[1], mins[1]);
4881 p->mins[2] = min(p->mins[2], mins[2]);
4882 p->maxs[0] = max(p->maxs[0], maxs[0]);
4883 p->maxs[1] = max(p->maxs[1], maxs[1]);
4884 p->maxs[2] = max(p->maxs[2], maxs[2]);
4886 // merge this surface's materialflags into the waterplane
4887 p->materialflags |= t->currentmaterialflags;
4888 if(!(p->materialflags & MATERIALFLAG_CAMERA))
4890 // merge this surface's PVS into the waterplane
4891 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4892 && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4894 r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4900 extern cvar_t r_drawparticles;
4901 extern cvar_t r_drawdecals;
4903 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4906 r_refdef_view_t originalview;
4907 r_refdef_view_t myview;
4908 int planeindex, qualityreduction = 0, old_r_dynamic = 0, old_r_shadows = 0, old_r_worldrtlight = 0, old_r_dlight = 0, old_r_particles = 0, old_r_decals = 0;
4909 r_waterstate_waterplane_t *p;
4911 r_rendertarget_t *rt;
4913 originalview = r_refdef.view;
4915 // lowquality hack, temporarily shut down some cvars and restore afterwards
4916 qualityreduction = r_water_lowquality.integer;
4917 if (qualityreduction > 0)
4919 if (qualityreduction >= 1)
4921 old_r_shadows = r_shadows.integer;
4922 old_r_worldrtlight = r_shadow_realtime_world.integer;
4923 old_r_dlight = r_shadow_realtime_dlight.integer;
4924 Cvar_SetValueQuick(&r_shadows, 0);
4925 Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4926 Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4928 if (qualityreduction >= 2)
4930 old_r_dynamic = r_dynamic.integer;
4931 old_r_particles = r_drawparticles.integer;
4932 old_r_decals = r_drawdecals.integer;
4933 Cvar_SetValueQuick(&r_dynamic, 0);
4934 Cvar_SetValueQuick(&r_drawparticles, 0);
4935 Cvar_SetValueQuick(&r_drawdecals, 0);
4939 for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4941 p->rt_reflection = NULL;
4942 p->rt_refraction = NULL;
4943 p->rt_camera = NULL;
4947 r_refdef.view = originalview;
4948 r_refdef.view.showdebug = false;
4949 r_refdef.view.width = r_fb.water.waterwidth;
4950 r_refdef.view.height = r_fb.water.waterheight;
4951 r_refdef.view.useclipplane = true;
4952 myview = r_refdef.view;
4953 r_fb.water.renderingscene = true;
4954 for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4956 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4959 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4961 rt = R_RenderTarget_Get(r_fb.water.waterwidth, r_fb.water.waterheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, r_fb.rt_screen->colortextype[0], TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
4962 if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4964 r_refdef.view = myview;
4965 Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4966 Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4967 if(r_water_scissormode.integer)
4969 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4970 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4972 p->rt_reflection = NULL;
4973 p->rt_refraction = NULL;
4974 p->rt_camera = NULL;
4979 r_refdef.view.clipplane = p->plane;
4980 // reflected view origin may be in solid, so don't cull with it
4981 r_refdef.view.usevieworiginculling = false;
4982 // reverse the cullface settings for this render
4983 r_refdef.view.cullface_front = GL_FRONT;
4984 r_refdef.view.cullface_back = GL_BACK;
4985 // combined pvs (based on what can be seen from each surface center)
4986 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4988 r_refdef.view.usecustompvs = true;
4990 memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4992 memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4995 r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4996 R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4997 GL_ScissorTest(false);
4998 R_ClearScreen(r_refdef.fogenabled);
4999 GL_ScissorTest(true);
5000 if(r_water_scissormode.integer & 2)
5001 R_View_UpdateWithScissor(myscissor);
5004 R_AnimCache_CacheVisibleEntities();
5005 if(r_water_scissormode.integer & 1)
5006 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
5007 R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5009 r_fb.water.hideplayer = false;
5010 p->rt_reflection = rt;
5013 // render the normal view scene and copy into texture
5014 // (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)
5015 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
5017 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);
5018 if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5020 r_refdef.view = myview;
5021 if(r_water_scissormode.integer)
5023 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
5024 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
5026 p->rt_reflection = NULL;
5027 p->rt_refraction = NULL;
5028 p->rt_camera = NULL;
5033 // combined pvs (based on what can be seen from each surface center)
5034 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
5036 r_refdef.view.usecustompvs = true;
5038 memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
5040 memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
5043 r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
5045 r_refdef.view.clipplane = p->plane;
5046 VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5047 r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5049 if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
5051 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5052 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
5053 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5054 R_RenderView_UpdateViewVectors();
5055 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5057 r_refdef.view.usecustompvs = true;
5058 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);
5062 PlaneClassify(&r_refdef.view.clipplane);
5064 R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5065 GL_ScissorTest(false);
5066 R_ClearScreen(r_refdef.fogenabled);
5067 GL_ScissorTest(true);
5068 if(r_water_scissormode.integer & 2)
5069 R_View_UpdateWithScissor(myscissor);
5072 R_AnimCache_CacheVisibleEntities();
5073 if(r_water_scissormode.integer & 1)
5074 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
5075 R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5077 r_fb.water.hideplayer = false;
5078 p->rt_refraction = rt;
5080 else if (p->materialflags & MATERIALFLAG_CAMERA)
5082 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);
5083 if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5085 r_refdef.view = myview;
5087 r_refdef.view.clipplane = p->plane;
5088 VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5089 r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5091 r_refdef.view.width = r_fb.water.camerawidth;
5092 r_refdef.view.height = r_fb.water.cameraheight;
5093 r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
5094 r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
5095 r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
5096 r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
5098 if(p->camera_entity)
5100 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5101 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5104 // note: all of the view is used for displaying... so
5105 // there is no use in scissoring
5107 // reverse the cullface settings for this render
5108 r_refdef.view.cullface_front = GL_FRONT;
5109 r_refdef.view.cullface_back = GL_BACK;
5110 // also reverse the view matrix
5111 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
5112 R_RenderView_UpdateViewVectors();
5113 if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5115 r_refdef.view.usecustompvs = true;
5116 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);
5119 // camera needs no clipplane
5120 r_refdef.view.useclipplane = false;
5121 // TODO: is the camera origin always valid? if so we don't need to clear this
5122 r_refdef.view.usevieworiginculling = false;
5124 PlaneClassify(&r_refdef.view.clipplane);
5126 r_fb.water.hideplayer = false;
5128 R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5129 GL_ScissorTest(false);
5130 R_ClearScreen(r_refdef.fogenabled);
5131 GL_ScissorTest(true);
5133 R_AnimCache_CacheVisibleEntities();
5134 R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5136 r_fb.water.hideplayer = false;
5141 r_fb.water.renderingscene = false;
5142 r_refdef.view = originalview;
5143 R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5145 R_AnimCache_CacheVisibleEntities();
5148 r_refdef.view = originalview;
5149 r_fb.water.renderingscene = false;
5150 Cvar_SetValueQuick(&r_water, 0);
5151 Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed! Turned off r_water.\n");
5153 // lowquality hack, restore cvars
5154 if (qualityreduction > 0)
5156 if (qualityreduction >= 1)
5158 Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5159 Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5160 Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5162 if (qualityreduction >= 2)
5164 Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5165 Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5166 Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5171 static void R_Bloom_StartFrame(void)
5173 int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
5174 int viewwidth, viewheight;
5175 textype_t textype = TEXTYPE_COLORBUFFER;
5177 // clear the pointers to rendertargets from last frame as they're stale
5178 r_fb.rt_screen = NULL;
5179 r_fb.rt_bloom = NULL;
5181 switch (vid.renderpath)
5183 case RENDERPATH_GL20:
5184 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5185 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5186 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5187 // for simplicity, bloom requires FBO render to texture, which basically all video drivers support now
5188 if (!vid.support.ext_framebuffer_object)
5191 case RENDERPATH_GLES2:
5192 r_fb.usedepthtextures = false;
5196 if (r_viewscale_fpsscaling.integer)
5198 double actualframetime;
5199 double targetframetime;
5201 actualframetime = r_refdef.lastdrawscreentime;
5202 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5203 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5204 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5205 if (r_viewscale_fpsscaling_stepsize.value > 0)
5206 adjust = (int)(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5207 viewscalefpsadjusted += adjust;
5208 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5211 viewscalefpsadjusted = 1.0f;
5213 R_GetScaledViewSize(r_refdef.view.width, r_refdef.view.height, &viewwidth, &viewheight);
5215 // set bloomwidth and bloomheight to the bloom resolution that will be
5216 // used (often less than the screen resolution for faster rendering)
5217 r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, vid.width);
5218 r_fb.bloomheight = r_fb.bloomwidth * vid.height / vid.width;
5219 r_fb.bloomheight = bound(1, r_fb.bloomheight, vid.height);
5220 r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5221 r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5223 // calculate desired texture sizes
5224 screentexturewidth = viewwidth;
5225 screentextureheight = viewheight;
5226 bloomtexturewidth = r_fb.bloomwidth;
5227 bloomtextureheight = r_fb.bloomheight;
5229 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))
5231 Cvar_SetValueQuick(&r_bloom, 0);
5232 Cvar_SetValueQuick(&r_motionblur, 0);
5233 Cvar_SetValueQuick(&r_damageblur, 0);
5236 // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5237 if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5239 if (r_fb.ghosttexture)
5240 R_FreeTexture(r_fb.ghosttexture);
5241 r_fb.ghosttexture = NULL;
5243 r_fb.screentexturewidth = screentexturewidth;
5244 r_fb.screentextureheight = screentextureheight;
5245 r_fb.textype = textype;
5247 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5249 if (r_motionblur.value > 0 || r_damageblur.value > 0)
5250 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);
5251 r_fb.ghosttexture_valid = false;
5255 if (r_bloom.integer)
5257 // bloom texture is a different resolution
5258 r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.width);
5259 r_fb.bloomheight = r_fb.bloomwidth * r_refdef.view.height / r_refdef.view.width;
5260 r_fb.bloomheight = bound(1, r_fb.bloomheight, r_refdef.view.height);
5263 r_fb.bloomwidth = r_fb.bloomheight = 0;
5265 r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5267 r_refdef.view.clear = true;
5270 static void R_Bloom_MakeTexture(void)
5273 float xoffset, yoffset, r, brighten;
5274 float colorscale = r_bloom_colorscale.value;
5275 r_viewport_t bloomviewport;
5276 r_rendertarget_t *prev, *cur;
5277 textype_t textype = r_fb.rt_screen->colortextype[0];
5279 r_refdef.stats[r_stat_bloom]++;
5281 R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5283 // scale down screen texture to the bloom texture size
5285 prev = r_fb.rt_screen;
5286 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5287 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5288 R_SetViewport(&bloomviewport);
5289 GL_CullFace(GL_NONE);
5290 GL_DepthTest(false);
5291 GL_BlendFunc(GL_ONE, GL_ZERO);
5292 GL_Color(colorscale, colorscale, colorscale, 1);
5293 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5294 // TODO: do boxfilter scale-down in shader?
5295 R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, true);
5296 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5297 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5298 // we now have a properly scaled bloom image
5300 // multiply bloom image by itself as many times as desired to darken it
5301 // TODO: if people actually use this it could be done more quickly in the previous shader pass
5302 for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5305 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5306 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5308 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5310 GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128);
5311 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5312 GL_Color(1,1,1,1); // no fix factor supported here
5313 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5314 R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, false);
5315 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5316 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5319 range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5320 brighten = r_bloom_brighten.value;
5321 brighten = sqrt(brighten);
5323 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5325 for (dir = 0;dir < 2;dir++)
5328 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5329 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5330 // blend on at multiple vertical offsets to achieve a vertical blur
5331 // TODO: do offset blends using GLSL
5332 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5333 GL_BlendFunc(GL_ONE, GL_ZERO);
5334 R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, false);
5335 for (x = -range;x <= range;x++)
5337 if (!dir){xoffset = 0;yoffset = x;}
5338 else {xoffset = x;yoffset = 0;}
5339 xoffset /= (float)prev->texturewidth;
5340 yoffset /= (float)prev->textureheight;
5341 // compute a texcoord array with the specified x and y offset
5342 r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5343 r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5344 r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5345 r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5346 r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5347 r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5348 r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5349 r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5350 // this r value looks like a 'dot' particle, fading sharply to
5351 // black at the edges
5352 // (probably not realistic but looks good enough)
5353 //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5354 //r = brighten/(range*2+1);
5355 r = brighten / (range * 2 + 1);
5357 r *= (1 - x*x/(float)((range+1)*(range+1)));
5360 GL_Color(r, r, r, 1);
5361 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5362 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5363 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5364 GL_BlendFunc(GL_ONE, GL_ONE);
5368 // now we have the bloom image, so keep track of it
5369 r_fb.rt_bloom = cur;
5372 static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5374 dpuint64 permutation;
5375 float uservecs[4][4];
5376 rtexture_t *viewtexture;
5377 rtexture_t *bloomtexture;
5379 R_EntityMatrix(&identitymatrix);
5381 if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
5383 // declare variables
5384 float blur_factor, blur_mouseaccel, blur_velocity;
5385 static float blur_average;
5386 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5388 // set a goal for the factoring
5389 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value)
5390 / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5391 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value)
5392 / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5393 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value)
5394 + (blur_mouseaccel * r_motionblur_mousefactor.value));
5396 // from the goal, pick an averaged value between goal and last value
5397 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5398 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5400 // enforce minimum amount of blur
5401 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5403 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5405 // calculate values into a standard alpha
5406 cl.motionbluralpha = 1 - exp(-
5408 (r_motionblur.value * blur_factor / 80)
5410 (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5413 max(0.0001, cl.time - cl.oldtime) // fps independent
5416 // randomization for the blur value to combat persistent ghosting
5417 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5418 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5421 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5422 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5424 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5425 GL_Color(1, 1, 1, cl.motionbluralpha);
5426 R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5427 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5428 R_SetupShader_Generic(r_fb.ghosttexture, NULL, GL_MODULATE, 1, false, true, true);
5429 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5430 r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5433 // updates old view angles for next pass
5434 VectorCopy(cl.viewangles, blur_oldangles);
5436 // copy view into the ghost texture
5437 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5438 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5439 r_fb.ghosttexture_valid = true;
5442 if (r_fb.bloomwidth)
5444 // make the bloom texture
5445 R_Bloom_MakeTexture();
5448 #if _MSC_VER >= 1400
5449 #define sscanf sscanf_s
5451 memset(uservecs, 0, sizeof(uservecs));
5452 if (r_glsl_postprocess_uservec1_enable.integer)
5453 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5454 if (r_glsl_postprocess_uservec2_enable.integer)
5455 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5456 if (r_glsl_postprocess_uservec3_enable.integer)
5457 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5458 if (r_glsl_postprocess_uservec4_enable.integer)
5459 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5461 // render to the screen fbo
5462 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5463 GL_Color(1, 1, 1, 1);
5464 GL_BlendFunc(GL_ONE, GL_ZERO);
5466 viewtexture = r_fb.rt_screen->colortexture[0];
5467 bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5469 if (r_rendertarget_debug.integer >= 0)
5471 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5472 if (rt && rt->colortexture[0])
5474 viewtexture = rt->colortexture[0];
5475 bloomtexture = NULL;
5479 R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5480 switch(vid.renderpath)
5482 case RENDERPATH_GL20:
5483 case RENDERPATH_GLES2:
5485 (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5486 | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5487 | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5488 | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5489 | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5490 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5491 if (r_glsl_permutation->tex_Texture_First >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , viewtexture);
5492 if (r_glsl_permutation->tex_Texture_Second >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second , bloomtexture);
5493 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps );
5494 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]);
5495 if (r_glsl_permutation->loc_PixelSize >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5496 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]);
5497 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]);
5498 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]);
5499 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]);
5500 if (r_glsl_permutation->loc_Saturation >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation , r_glsl_saturation.value);
5501 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
5502 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);
5505 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5506 r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5509 matrix4x4_t r_waterscrollmatrix;
5511 void R_UpdateFog(void)
5514 if (gamemode == GAME_NEHAHRA)
5516 if (gl_fogenable.integer)
5518 r_refdef.oldgl_fogenable = true;
5519 r_refdef.fog_density = gl_fogdensity.value;
5520 r_refdef.fog_red = gl_fogred.value;
5521 r_refdef.fog_green = gl_foggreen.value;
5522 r_refdef.fog_blue = gl_fogblue.value;
5523 r_refdef.fog_alpha = 1;
5524 r_refdef.fog_start = 0;
5525 r_refdef.fog_end = gl_skyclip.value;
5526 r_refdef.fog_height = 1<<30;
5527 r_refdef.fog_fadedepth = 128;
5529 else if (r_refdef.oldgl_fogenable)
5531 r_refdef.oldgl_fogenable = false;
5532 r_refdef.fog_density = 0;
5533 r_refdef.fog_red = 0;
5534 r_refdef.fog_green = 0;
5535 r_refdef.fog_blue = 0;
5536 r_refdef.fog_alpha = 0;
5537 r_refdef.fog_start = 0;
5538 r_refdef.fog_end = 0;
5539 r_refdef.fog_height = 1<<30;
5540 r_refdef.fog_fadedepth = 128;
5545 r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5546 r_refdef.fog_start = max(0, r_refdef.fog_start);
5547 r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5549 if (r_refdef.fog_density && r_drawfog.integer)
5551 r_refdef.fogenabled = true;
5552 // this is the point where the fog reaches 0.9986 alpha, which we
5553 // consider a good enough cutoff point for the texture
5554 // (0.9986 * 256 == 255.6)
5555 if (r_fog_exp2.integer)
5556 r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5558 r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5559 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5560 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5561 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5562 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5563 R_BuildFogHeightTexture();
5564 // fog color was already set
5565 // update the fog texture
5566 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)
5567 R_BuildFogTexture();
5568 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5569 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5572 r_refdef.fogenabled = false;
5575 if (r_refdef.fog_density)
5577 r_refdef.fogcolor[0] = r_refdef.fog_red;
5578 r_refdef.fogcolor[1] = r_refdef.fog_green;
5579 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5581 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5582 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5583 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5584 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5588 VectorCopy(r_refdef.fogcolor, fogvec);
5589 // color.rgb *= ContrastBoost * SceneBrightness;
5590 VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5591 r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5592 r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5593 r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5598 void R_UpdateVariables(void)
5602 r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5604 r_refdef.farclip = r_farclip_base.value;
5605 if (r_refdef.scene.worldmodel)
5606 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5607 r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5609 if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5610 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5611 r_refdef.polygonfactor = 0;
5612 r_refdef.polygonoffset = 0;
5613 r_refdef.shadowpolygonfactor = r_refdef.polygonfactor + r_shadow_polygonfactor.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
5614 r_refdef.shadowpolygonoffset = r_refdef.polygonoffset + r_shadow_polygonoffset.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
5616 r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5617 r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5618 r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5619 r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5620 r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5621 if (FAKELIGHT_ENABLED)
5623 r_refdef.scene.lightmapintensity *= r_fakelight_intensity.value;
5625 else if (r_refdef.scene.worldmodel)
5627 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5629 if (r_showsurfaces.integer)
5631 r_refdef.scene.rtworld = false;
5632 r_refdef.scene.rtworldshadows = false;
5633 r_refdef.scene.rtdlight = false;
5634 r_refdef.scene.rtdlightshadows = false;
5635 r_refdef.scene.lightmapintensity = 0;
5638 r_gpuskeletal = false;
5639 switch(vid.renderpath)
5641 case RENDERPATH_GL20:
5642 r_gpuskeletal = vid.support.arb_uniform_buffer_object && r_glsl_skeletal.integer && !r_showsurfaces.integer; // FIXME add r_showsurfaces support to GLSL skeletal!
5643 case RENDERPATH_GLES2:
5644 if(!vid_gammatables_trivial)
5646 if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5648 // build GLSL gamma texture
5649 #define RAMPWIDTH 256
5650 unsigned short ramp[RAMPWIDTH * 3];
5651 unsigned char rampbgr[RAMPWIDTH][4];
5654 r_texture_gammaramps_serial = vid_gammatables_serial;
5656 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5657 for(i = 0; i < RAMPWIDTH; ++i)
5659 rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5660 rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5661 rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5664 if (r_texture_gammaramps)
5666 R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1);
5670 r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5676 // remove GLSL gamma texture
5682 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5683 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5689 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5690 if( scenetype != r_currentscenetype ) {
5691 // store the old scenetype
5692 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5693 r_currentscenetype = scenetype;
5694 // move in the new scene
5695 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5704 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5706 // of course, we could also add a qboolean that provides a lock state and a ReleaseScenePointer function..
5707 if( scenetype == r_currentscenetype ) {
5708 return &r_refdef.scene;
5710 return &r_scenes_store[ scenetype ];
5714 static int R_SortEntities_Compare(const void *ap, const void *bp)
5716 const entity_render_t *a = *(const entity_render_t **)ap;
5717 const entity_render_t *b = *(const entity_render_t **)bp;
5720 if(a->model < b->model)
5722 if(a->model > b->model)
5726 // TODO possibly calculate the REAL skinnum here first using
5728 if(a->skinnum < b->skinnum)
5730 if(a->skinnum > b->skinnum)
5733 // everything we compared is equal
5736 static void R_SortEntities(void)
5738 // below or equal 2 ents, sorting never gains anything
5739 if(r_refdef.scene.numentities <= 2)
5742 qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5750 extern cvar_t r_shadow_bouncegrid;
5751 extern cvar_t v_isometric;
5752 extern void V_MakeViewIsometric(void);
5753 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5755 matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5757 rtexture_t *viewdepthtexture = NULL;
5758 rtexture_t *viewcolortexture = NULL;
5759 int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5761 // finish any 2D rendering that was queued
5764 if (r_timereport_active)
5765 R_TimeReport("start");
5766 r_textureframe++; // used only by R_GetCurrentTexture
5767 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5769 if(R_CompileShader_CheckStaticParms())
5772 if (!r_drawentities.integer)
5773 r_refdef.scene.numentities = 0;
5774 else if (r_sortentities.integer)
5777 R_AnimCache_ClearCache();
5779 /* adjust for stereo display */
5780 if(R_Stereo_Active())
5782 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);
5783 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5786 if (r_refdef.view.isoverlay)
5788 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5789 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5790 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5791 R_TimeReport("depthclear");
5793 r_refdef.view.showdebug = false;
5795 r_fb.water.enabled = false;
5796 r_fb.water.numwaterplanes = 0;
5798 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5800 r_refdef.view.matrix = originalmatrix;
5806 if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5808 r_refdef.view.matrix = originalmatrix;
5812 r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5813 if (v_isometric.integer && r_refdef.view.ismain)
5814 V_MakeViewIsometric();
5816 r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5818 if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5819 // in sRGB fallback, behave similar to true sRGB: convert this
5820 // value from linear to sRGB
5821 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5823 R_RenderView_UpdateViewVectors();
5825 R_Shadow_UpdateWorldLightSelection();
5827 // this will set up r_fb.rt_screen
5828 R_Bloom_StartFrame();
5830 // apply bloom brightness offset
5832 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5834 // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5837 viewfbo = r_fb.rt_screen->fbo;
5838 viewdepthtexture = r_fb.rt_screen->depthtexture;
5839 viewcolortexture = r_fb.rt_screen->colortexture[0];
5843 viewheight = height;
5846 R_Water_StartFrame();
5849 if (r_timereport_active)
5850 R_TimeReport("viewsetup");
5852 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5854 // clear the whole fbo every frame - otherwise the driver will consider
5855 // it to be an inter-frame texture and stall in multi-gpu configurations
5857 GL_ScissorTest(false);
5858 R_ClearScreen(r_refdef.fogenabled);
5859 if (r_timereport_active)
5860 R_TimeReport("viewclear");
5862 r_refdef.view.clear = true;
5864 r_refdef.view.showdebug = true;
5867 if (r_timereport_active)
5868 R_TimeReport("visibility");
5870 R_AnimCache_CacheVisibleEntities();
5871 if (r_timereport_active)
5872 R_TimeReport("animcache");
5874 R_Shadow_UpdateBounceGridTexture();
5875 if (r_timereport_active && r_shadow_bouncegrid.integer)
5876 R_TimeReport("bouncegrid");
5878 r_fb.water.numwaterplanes = 0;
5879 if (r_fb.water.enabled)
5880 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5882 // for the actual view render we use scissoring a fair amount, so scissor
5883 // test needs to be on
5885 GL_ScissorTest(true);
5886 GL_Scissor(viewx, viewy, viewwidth, viewheight);
5887 R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5888 r_fb.water.numwaterplanes = 0;
5890 // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5891 GL_ScissorTest(false);
5893 R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
5894 if (r_timereport_active)
5895 R_TimeReport("blendview");
5897 r_refdef.view.matrix = originalmatrix;
5901 // go back to 2d rendering
5905 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5907 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5909 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5910 if (r_timereport_active)
5911 R_TimeReport("waterworld");
5914 // don't let sound skip if going slow
5915 if (r_refdef.scene.extraupdate)
5918 R_DrawModelsAddWaterPlanes();
5919 if (r_timereport_active)
5920 R_TimeReport("watermodels");
5922 if (r_fb.water.numwaterplanes)
5924 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5925 if (r_timereport_active)
5926 R_TimeReport("waterscenes");
5930 extern cvar_t cl_locs_show;
5931 static void R_DrawLocs(void);
5932 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5933 static void R_DrawModelDecals(void);
5934 extern cvar_t cl_decals_newsystem;
5935 extern qboolean r_shadow_usingdeferredprepass;
5936 extern int r_shadow_shadowmapatlas_modelshadows_size;
5937 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5939 qboolean shadowmapping = false;
5941 if (r_timereport_active)
5942 R_TimeReport("beginscene");
5944 r_refdef.stats[r_stat_renders]++;
5948 // don't let sound skip if going slow
5949 if (r_refdef.scene.extraupdate)
5952 R_MeshQueue_BeginScene();
5956 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);
5958 if (r_timereport_active)
5959 R_TimeReport("skystartframe");
5961 if (cl.csqc_vidvars.drawworld)
5963 // don't let sound skip if going slow
5964 if (r_refdef.scene.extraupdate)
5967 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5969 r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5970 if (r_timereport_active)
5971 R_TimeReport("worldsky");
5974 if (R_DrawBrushModelsSky() && r_timereport_active)
5975 R_TimeReport("bmodelsky");
5977 if (skyrendermasked && skyrenderlater)
5979 // we have to force off the water clipping plane while rendering sky
5980 R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5982 R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5983 if (r_timereport_active)
5984 R_TimeReport("sky");
5988 // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5989 r_shadow_viewfbo = viewfbo;
5990 r_shadow_viewdepthtexture = viewdepthtexture;
5991 r_shadow_viewcolortexture = viewcolortexture;
5992 r_shadow_viewx = viewx;
5993 r_shadow_viewy = viewy;
5994 r_shadow_viewwidth = viewwidth;
5995 r_shadow_viewheight = viewheight;
5997 R_Shadow_PrepareModelShadows();
5998 R_Shadow_PrepareLights();
5999 if (r_timereport_active)
6000 R_TimeReport("preparelights");
6002 // render all the shadowmaps that will be used for this view
6003 shadowmapping = R_Shadow_ShadowMappingEnabled();
6004 if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
6006 R_Shadow_DrawShadowMaps();
6007 if (r_timereport_active)
6008 R_TimeReport("shadowmaps");
6011 // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
6012 if (r_shadow_usingdeferredprepass)
6013 R_Shadow_DrawPrepass();
6015 // now we begin the forward pass of the view render
6016 if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
6018 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
6019 if (r_timereport_active)
6020 R_TimeReport("worlddepth");
6022 if (r_depthfirst.integer >= 2)
6024 R_DrawModelsDepth();
6025 if (r_timereport_active)
6026 R_TimeReport("modeldepth");
6029 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
6031 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
6032 if (r_timereport_active)
6033 R_TimeReport("world");
6036 // don't let sound skip if going slow
6037 if (r_refdef.scene.extraupdate)
6041 if (r_timereport_active)
6042 R_TimeReport("models");
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 (!r_shadow_usingdeferredprepass)
6060 R_Shadow_DrawLights();
6061 if (r_timereport_active)
6062 R_TimeReport("rtlights");
6065 // don't let sound skip if going slow
6066 if (r_refdef.scene.extraupdate)
6069 if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && r_shadows_drawafterrtlighting.integer && r_refdef.scene.lightmapintensity > 0)
6071 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6072 R_Shadow_DrawModelShadows();
6073 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6074 // don't let sound skip if going slow
6075 if (r_refdef.scene.extraupdate)
6079 if (cl.csqc_vidvars.drawworld)
6081 if (cl_decals_newsystem.integer)
6083 R_DrawModelDecals();
6084 if (r_timereport_active)
6085 R_TimeReport("modeldecals");
6090 if (r_timereport_active)
6091 R_TimeReport("decals");
6095 if (r_timereport_active)
6096 R_TimeReport("particles");
6099 if (r_timereport_active)
6100 R_TimeReport("explosions");
6103 if (r_refdef.view.showdebug)
6105 if (cl_locs_show.integer)
6108 if (r_timereport_active)
6109 R_TimeReport("showlocs");
6112 if (r_drawportals.integer)
6115 if (r_timereport_active)
6116 R_TimeReport("portals");
6119 if (r_showbboxes_client.value > 0)
6121 R_DrawEntityBBoxes(CLVM_prog);
6122 if (r_timereport_active)
6123 R_TimeReport("clbboxes");
6125 if (r_showbboxes.value > 0)
6127 R_DrawEntityBBoxes(SVVM_prog);
6128 if (r_timereport_active)
6129 R_TimeReport("svbboxes");
6133 if (r_transparent.integer)
6135 R_MeshQueue_RenderTransparent();
6136 if (r_timereport_active)
6137 R_TimeReport("drawtrans");
6140 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))
6142 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
6143 if (r_timereport_active)
6144 R_TimeReport("worlddebug");
6145 R_DrawModelsDebug();
6146 if (r_timereport_active)
6147 R_TimeReport("modeldebug");
6150 if (cl.csqc_vidvars.drawworld)
6152 R_Shadow_DrawCoronas();
6153 if (r_timereport_active)
6154 R_TimeReport("coronas");
6157 // don't let sound skip if going slow
6158 if (r_refdef.scene.extraupdate)
6162 static const unsigned short bboxelements[36] =
6172 #define BBOXEDGES 13
6173 static const float bboxedges[BBOXEDGES][6] =
6176 { 0, 0, 0, 1, 1, 1 },
6178 { 0, 0, 0, 0, 1, 0 },
6179 { 0, 0, 0, 1, 0, 0 },
6180 { 0, 1, 0, 1, 1, 0 },
6181 { 1, 0, 0, 1, 1, 0 },
6183 { 0, 0, 1, 0, 1, 1 },
6184 { 0, 0, 1, 1, 0, 1 },
6185 { 0, 1, 1, 1, 1, 1 },
6186 { 1, 0, 1, 1, 1, 1 },
6188 { 0, 0, 0, 0, 0, 1 },
6189 { 1, 0, 0, 1, 0, 1 },
6190 { 0, 1, 0, 0, 1, 1 },
6191 { 1, 1, 0, 1, 1, 1 },
6194 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6196 int numvertices = BBOXEDGES * 8;
6197 float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6198 int numtriangles = BBOXEDGES * 12;
6199 unsigned short elements[BBOXEDGES * 36];
6201 float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6203 RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6205 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6206 GL_DepthMask(false);
6207 GL_DepthRange(0, 1);
6208 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6210 for (edge = 0; edge < BBOXEDGES; edge++)
6212 for (i = 0; i < 3; i++)
6214 edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6215 edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6217 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6218 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6219 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6220 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6221 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6222 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6223 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6224 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6225 for (i = 0; i < 36; i++)
6226 elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6228 R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6229 if (r_refdef.fogenabled)
6231 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6233 f1 = RSurf_FogVertex(v);
6235 c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6236 c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6237 c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6240 R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6241 R_Mesh_ResetTextureState();
6242 R_SetupShader_Generic_NoTexture(false, false);
6243 R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6246 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6248 // hacky overloading of the parameters
6249 prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6252 prvm_edict_t *edict;
6254 GL_CullFace(GL_NONE);
6255 R_SetupShader_Generic_NoTexture(false, false);
6257 for (i = 0;i < numsurfaces;i++)
6259 edict = PRVM_EDICT_NUM(surfacelist[i]);
6260 switch ((int)PRVM_serveredictfloat(edict, solid))
6262 case SOLID_NOT: Vector4Set(color, 1, 1, 1, 0.05);break;
6263 case SOLID_TRIGGER: Vector4Set(color, 1, 0, 1, 0.10);break;
6264 case SOLID_BBOX: Vector4Set(color, 0, 1, 0, 0.10);break;
6265 case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6266 case SOLID_BSP: Vector4Set(color, 0, 0, 1, 0.05);break;
6267 case SOLID_CORPSE: Vector4Set(color, 1, 0.5, 0, 0.05);break;
6268 default: Vector4Set(color, 0, 0, 0, 0.50);break;
6270 if (prog == CLVM_prog)
6271 color[3] *= r_showbboxes_client.value;
6273 color[3] *= r_showbboxes.value;
6274 color[3] = bound(0, color[3], 1);
6275 GL_DepthTest(!r_showdisabledepthtest.integer);
6276 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6280 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6283 prvm_edict_t *edict;
6289 for (i = 0; i < prog->num_edicts; i++)
6291 edict = PRVM_EDICT_NUM(i);
6292 if (edict->priv.server->free)
6294 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6295 if (PRVM_serveredictedict(edict, tag_entity) != 0)
6297 if (PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6299 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6300 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6304 static const int nomodelelement3i[24] =
6316 static const unsigned short nomodelelement3s[24] =
6328 static const float nomodelvertex3f[6*3] =
6338 static const float nomodelcolor4f[6*4] =
6340 0.0f, 0.0f, 0.5f, 1.0f,
6341 0.0f, 0.0f, 0.5f, 1.0f,
6342 0.0f, 0.5f, 0.0f, 1.0f,
6343 0.0f, 0.5f, 0.0f, 1.0f,
6344 0.5f, 0.0f, 0.0f, 1.0f,
6345 0.5f, 0.0f, 0.0f, 1.0f
6348 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6354 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);
6356 // this is only called once per entity so numsurfaces is always 1, and
6357 // surfacelist is always {0}, so this code does not handle batches
6359 if (rsurface.ent_flags & RENDER_ADDITIVE)
6361 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6362 GL_DepthMask(false);
6364 else if (ent->alpha < 1)
6366 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6367 GL_DepthMask(false);
6371 GL_BlendFunc(GL_ONE, GL_ZERO);
6374 GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6375 GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6376 GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6377 GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6378 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6379 for (i = 0, c = color4f;i < 6;i++, c += 4)
6381 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6382 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6383 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6386 if (r_refdef.fogenabled)
6388 for (i = 0, c = color4f;i < 6;i++, c += 4)
6390 f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6392 c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6393 c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6394 c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6397 // R_Mesh_ResetTextureState();
6398 R_SetupShader_Generic_NoTexture(false, false);
6399 R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6400 R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6403 void R_DrawNoModel(entity_render_t *ent)
6406 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6407 if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6408 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6410 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6413 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6415 vec3_t right1, right2, diff, normal;
6417 VectorSubtract (org2, org1, normal);
6419 // calculate 'right' vector for start
6420 VectorSubtract (r_refdef.view.origin, org1, diff);
6421 CrossProduct (normal, diff, right1);
6422 VectorNormalize (right1);
6424 // calculate 'right' vector for end
6425 VectorSubtract (r_refdef.view.origin, org2, diff);
6426 CrossProduct (normal, diff, right2);
6427 VectorNormalize (right2);
6429 vert[ 0] = org1[0] + width * right1[0];
6430 vert[ 1] = org1[1] + width * right1[1];
6431 vert[ 2] = org1[2] + width * right1[2];
6432 vert[ 3] = org1[0] - width * right1[0];
6433 vert[ 4] = org1[1] - width * right1[1];
6434 vert[ 5] = org1[2] - width * right1[2];
6435 vert[ 6] = org2[0] - width * right2[0];
6436 vert[ 7] = org2[1] - width * right2[1];
6437 vert[ 8] = org2[2] - width * right2[2];
6438 vert[ 9] = org2[0] + width * right2[0];
6439 vert[10] = org2[1] + width * right2[1];
6440 vert[11] = org2[2] + width * right2[2];
6443 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)
6445 vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6446 vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6447 vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6448 vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6449 vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6450 vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6451 vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6452 vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6453 vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6454 vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6455 vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6456 vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6459 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6464 VectorSet(v, x, y, z);
6465 for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6466 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6468 if (i == mesh->numvertices)
6470 if (mesh->numvertices < mesh->maxvertices)
6472 VectorCopy(v, vertex3f);
6473 mesh->numvertices++;
6475 return mesh->numvertices;
6481 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6485 element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6486 element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6487 e = mesh->element3i + mesh->numtriangles * 3;
6488 for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6490 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6491 if (mesh->numtriangles < mesh->maxtriangles)
6496 mesh->numtriangles++;
6498 element[1] = element[2];
6502 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6506 element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6507 element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6508 e = mesh->element3i + mesh->numtriangles * 3;
6509 for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6511 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6512 if (mesh->numtriangles < mesh->maxtriangles)
6517 mesh->numtriangles++;
6519 element[1] = element[2];
6523 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6524 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6526 int planenum, planenum2;
6529 mplane_t *plane, *plane2;
6531 double temppoints[2][256*3];
6532 // figure out how large a bounding box we need to properly compute this brush
6534 for (w = 0;w < numplanes;w++)
6535 maxdist = max(maxdist, fabs(planes[w].dist));
6536 // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6537 maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6538 for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6542 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6543 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6545 if (planenum2 == planenum)
6547 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);
6550 if (tempnumpoints < 3)
6552 // generate elements forming a triangle fan for this polygon
6553 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6557 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)
6559 texturelayer_t *layer;
6560 layer = t->currentlayers + t->currentnumlayers++;
6562 layer->depthmask = depthmask;
6563 layer->blendfunc1 = blendfunc1;
6564 layer->blendfunc2 = blendfunc2;
6565 layer->texture = texture;
6566 layer->texmatrix = *matrix;
6567 layer->color[0] = r;
6568 layer->color[1] = g;
6569 layer->color[2] = b;
6570 layer->color[3] = a;
6573 static qboolean R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6575 if(parms[0] == 0 && parms[1] == 0)
6577 if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6578 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6583 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6586 index = parms[2] + rsurface.shadertime * parms[3];
6587 index -= floor(index);
6588 switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6591 case Q3WAVEFUNC_NONE:
6592 case Q3WAVEFUNC_NOISE:
6593 case Q3WAVEFUNC_COUNT:
6596 case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6597 case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6598 case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6599 case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6600 case Q3WAVEFUNC_TRIANGLE:
6602 f = index - floor(index);
6615 f = parms[0] + parms[1] * f;
6616 if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6617 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6621 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6628 matrix4x4_t matrix, temp;
6629 // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6630 // it's better to have one huge fixup every 9 hours than gradual
6631 // degradation over time which looks consistently bad after many hours.
6633 // tcmod scroll in particular suffers from this degradation which can't be
6634 // effectively worked around even with floor() tricks because we don't
6635 // know if tcmod scroll is the last tcmod being applied, and for clampmap
6636 // a workaround involving floor() would be incorrect anyway...
6637 shadertime = rsurface.shadertime;
6638 if (shadertime >= 32768.0f)
6639 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6640 switch(tcmod->tcmod)
6644 if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6645 matrix = r_waterscrollmatrix;
6647 matrix = identitymatrix;
6649 case Q3TCMOD_ENTITYTRANSLATE:
6650 // this is used in Q3 to allow the gamecode to control texcoord
6651 // scrolling on the entity, which is not supported in darkplaces yet.
6652 Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6654 case Q3TCMOD_ROTATE:
6655 Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6656 Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6657 Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6660 Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6662 case Q3TCMOD_SCROLL:
6663 // this particular tcmod is a "bug for bug" compatible one with regards to
6664 // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6665 // specifically did the wrapping and so we must mimic that...
6666 offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6667 offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6668 Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6670 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6671 w = (int) tcmod->parms[0];
6672 h = (int) tcmod->parms[1];
6673 f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6675 idx = (int) floor(f * w * h);
6676 Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6678 case Q3TCMOD_STRETCH:
6679 f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6680 Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6682 case Q3TCMOD_TRANSFORM:
6683 VectorSet(tcmat + 0, tcmod->parms[0], tcmod->parms[1], 0);
6684 VectorSet(tcmat + 3, tcmod->parms[2], tcmod->parms[3], 0);
6685 VectorSet(tcmat + 6, 0 , 0 , 1);
6686 VectorSet(tcmat + 9, tcmod->parms[4], tcmod->parms[5], 0);
6687 Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6689 case Q3TCMOD_TURBULENT:
6690 // this is handled in the RSurf_PrepareVertices function
6691 matrix = identitymatrix;
6695 Matrix4x4_Concat(texmatrix, &matrix, &temp);
6698 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6700 int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6701 char name[MAX_QPATH];
6702 skinframe_t *skinframe;
6703 unsigned char pixels[296*194];
6704 strlcpy(cache->name, skinname, sizeof(cache->name));
6705 dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6706 if (developer_loading.integer)
6707 Con_Printf("loading %s\n", name);
6708 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6709 if (!skinframe || !skinframe->base)
6712 fs_offset_t filesize;
6714 f = FS_LoadFile(name, tempmempool, true, &filesize);
6717 if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6718 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6722 cache->skinframe = skinframe;
6725 texture_t *R_GetCurrentTexture(texture_t *t)
6728 const entity_render_t *ent = rsurface.entity;
6729 dp_model_t *model = ent->model; // when calling this, ent must not be NULL
6730 q3shaderinfo_layer_tcmod_t *tcmod;
6731 float specularscale = 0.0f;
6733 if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6734 return t->currentframe;
6735 t->update_lastrenderframe = r_textureframe;
6736 t->update_lastrenderentity = (void *)ent;
6738 if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6739 t->camera_entity = ent->entitynumber;
6741 t->camera_entity = 0;
6743 // switch to an alternate material if this is a q1bsp animated material
6745 texture_t *texture = t;
6746 int s = rsurface.ent_skinnum;
6747 if ((unsigned int)s >= (unsigned int)model->numskins)
6749 if (model->skinscenes)
6751 if (model->skinscenes[s].framecount > 1)
6752 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6754 s = model->skinscenes[s].firstframe;
6757 t = t + s * model->num_surfaces;
6760 // use an alternate animation if the entity's frame is not 0,
6761 // and only if the texture has an alternate animation
6762 if (t->animated == 2) // q2bsp
6763 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6764 else if (rsurface.ent_alttextures && t->anim_total[1])
6765 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6767 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6769 texture->currentframe = t;
6772 // update currentskinframe to be a qw skin or animation frame
6773 if (rsurface.ent_qwskin >= 0)
6775 i = rsurface.ent_qwskin;
6776 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6778 r_qwskincache_size = cl.maxclients;
6780 Mem_Free(r_qwskincache);
6781 r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6783 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6784 R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6785 t->currentskinframe = r_qwskincache[i].skinframe;
6786 if (t->materialshaderpass && t->currentskinframe == NULL)
6787 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6789 else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6790 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6791 if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6792 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6794 t->currentmaterialflags = t->basematerialflags;
6795 t->currentalpha = rsurface.entity->alpha * t->basealpha;
6796 if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_water.integer || r_novis.integer || r_trippy.integer))
6797 t->currentalpha *= r_wateralpha.value;
6798 if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6799 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6800 if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6801 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6803 // decide on which type of lighting to use for this surface
6804 if (rsurface.entity->render_modellight_forced)
6805 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6806 if (rsurface.entity->render_rtlight_disabled)
6807 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6808 if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6810 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6811 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT;
6812 for (q = 0; q < 3; q++)
6814 t->render_glowmod[q] = rsurface.entity->glowmod[q];
6815 t->render_modellight_lightdir[q] = q == 2;
6816 t->render_modellight_ambient[q] = 1;
6817 t->render_modellight_diffuse[q] = 0;
6818 t->render_modellight_specular[q] = 0;
6819 t->render_lightmap_ambient[q] = 0;
6820 t->render_lightmap_diffuse[q] = 0;
6821 t->render_lightmap_specular[q] = 0;
6822 t->render_rtlight_diffuse[q] = 0;
6823 t->render_rtlight_specular[q] = 0;
6826 else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6828 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6829 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT;
6830 for (q = 0; q < 3; q++)
6832 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6833 t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6834 t->render_modellight_lightdir[q] = q == 2;
6835 t->render_modellight_diffuse[q] = 0;
6836 t->render_modellight_specular[q] = 0;
6837 t->render_lightmap_ambient[q] = 0;
6838 t->render_lightmap_diffuse[q] = 0;
6839 t->render_lightmap_specular[q] = 0;
6840 t->render_rtlight_diffuse[q] = 0;
6841 t->render_rtlight_specular[q] = 0;
6844 else if (FAKELIGHT_ENABLED)
6846 // no modellight if using fakelight for the map
6847 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_NORTLIGHT) & ~(MATERIALFLAG_MODELLIGHT);
6848 for (q = 0; q < 3; q++)
6850 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6851 t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6852 t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6853 t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6854 t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6855 t->render_lightmap_ambient[q] = 0;
6856 t->render_lightmap_diffuse[q] = 0;
6857 t->render_lightmap_specular[q] = 0;
6858 t->render_rtlight_diffuse[q] = 0;
6859 t->render_rtlight_specular[q] = 0;
6862 else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6864 // ambient + single direction light (modellight)
6865 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6866 for (q = 0; q < 3; q++)
6868 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6869 t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6870 t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6871 t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6872 t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6873 t->render_lightmap_ambient[q] = 0;
6874 t->render_lightmap_diffuse[q] = 0;
6875 t->render_lightmap_specular[q] = 0;
6876 t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6877 t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6882 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6883 for (q = 0; q < 3; q++)
6885 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6886 t->render_modellight_lightdir[q] = q == 2;
6887 t->render_modellight_ambient[q] = 0;
6888 t->render_modellight_diffuse[q] = 0;
6889 t->render_modellight_specular[q] = 0;
6890 t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6891 t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6892 t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6893 t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6894 t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6898 if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6900 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6901 // attribute, we punt it to the lightmap path and hope for the best,
6902 // but lighting doesn't work.
6904 // FIXME: this is fine for effects but CSQC polygons should be subject
6906 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6907 for (q = 0; q < 3; q++)
6909 t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6910 t->render_modellight_lightdir[q] = q == 2;
6911 t->render_modellight_ambient[q] = 0;
6912 t->render_modellight_diffuse[q] = 0;
6913 t->render_modellight_specular[q] = 0;
6914 t->render_lightmap_ambient[q] = 0;
6915 t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6916 t->render_lightmap_specular[q] = 0;
6917 t->render_rtlight_diffuse[q] = 0;
6918 t->render_rtlight_specular[q] = 0;
6922 for (q = 0; q < 3; q++)
6924 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6925 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6928 if (rsurface.ent_flags & RENDER_ADDITIVE)
6929 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6930 else if (t->currentalpha < 1)
6931 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6932 // LordHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6933 if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6934 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6935 if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6936 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6937 if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6938 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6939 if (t->backgroundshaderpass)
6940 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6941 if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6943 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6944 t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6947 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6948 if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6950 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6951 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6953 if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6954 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6956 // there is no tcmod
6957 if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6959 t->currenttexmatrix = r_waterscrollmatrix;
6960 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6962 else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6964 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6965 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6968 if (t->materialshaderpass)
6969 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6970 R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6972 t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6973 if (t->currentskinframe->qpixels)
6974 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6975 t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6976 if (!t->basetexture)
6977 t->basetexture = r_texture_notexture;
6978 t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6979 t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6980 t->nmaptexture = t->currentskinframe->nmap;
6981 if (!t->nmaptexture)
6982 t->nmaptexture = r_texture_blanknormalmap;
6983 t->glosstexture = r_texture_black;
6984 t->glowtexture = t->currentskinframe->glow;
6985 t->fogtexture = t->currentskinframe->fog;
6986 t->reflectmasktexture = t->currentskinframe->reflect;
6987 if (t->backgroundshaderpass)
6989 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6990 R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6991 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6992 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6993 t->backgroundglosstexture = r_texture_black;
6994 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6995 if (!t->backgroundnmaptexture)
6996 t->backgroundnmaptexture = r_texture_blanknormalmap;
6997 // make sure that if glow is going to be used, both textures are not NULL
6998 if (!t->backgroundglowtexture && t->glowtexture)
6999 t->backgroundglowtexture = r_texture_black;
7000 if (!t->glowtexture && t->backgroundglowtexture)
7001 t->glowtexture = r_texture_black;
7005 t->backgroundbasetexture = r_texture_white;
7006 t->backgroundnmaptexture = r_texture_blanknormalmap;
7007 t->backgroundglosstexture = r_texture_black;
7008 t->backgroundglowtexture = NULL;
7010 t->specularpower = r_shadow_glossexponent.value;
7011 // TODO: store reference values for these in the texture?
7012 if (r_shadow_gloss.integer > 0)
7014 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
7016 if (r_shadow_glossintensity.value > 0)
7018 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
7019 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
7020 specularscale = r_shadow_glossintensity.value;
7023 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
7025 t->glosstexture = r_texture_white;
7026 t->backgroundglosstexture = r_texture_white;
7027 specularscale = r_shadow_gloss2intensity.value;
7028 t->specularpower = r_shadow_gloss2exponent.value;
7031 specularscale *= t->specularscalemod;
7032 t->specularpower *= t->specularpowermod;
7034 // lightmaps mode looks bad with dlights using actual texturing, so turn
7035 // off the colormap and glossmap, but leave the normalmap on as it still
7036 // accurately represents the shading involved
7037 if (gl_lightmaps.integer)
7039 t->basetexture = r_texture_grey128;
7040 t->pantstexture = r_texture_black;
7041 t->shirttexture = r_texture_black;
7042 if (gl_lightmaps.integer < 2)
7043 t->nmaptexture = r_texture_blanknormalmap;
7044 t->glosstexture = r_texture_black;
7045 t->glowtexture = NULL;
7046 t->fogtexture = NULL;
7047 t->reflectmasktexture = NULL;
7048 t->backgroundbasetexture = NULL;
7049 if (gl_lightmaps.integer < 2)
7050 t->backgroundnmaptexture = r_texture_blanknormalmap;
7051 t->backgroundglosstexture = r_texture_black;
7052 t->backgroundglowtexture = NULL;
7054 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
7057 if (specularscale != 1.0f)
7059 for (q = 0; q < 3; q++)
7061 t->render_modellight_specular[q] *= specularscale;
7062 t->render_lightmap_specular[q] *= specularscale;
7063 t->render_rtlight_specular[q] *= specularscale;
7067 t->currentnumlayers = 0;
7068 if (t->currentmaterialflags & MATERIALFLAG_WALL)
7070 int blendfunc1, blendfunc2;
7072 if (t->currentmaterialflags & MATERIALFLAG_ADD)
7074 blendfunc1 = GL_SRC_ALPHA;
7075 blendfunc2 = GL_ONE;
7077 else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
7079 blendfunc1 = GL_SRC_ALPHA;
7080 blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
7082 else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
7084 blendfunc1 = t->customblendfunc[0];
7085 blendfunc2 = t->customblendfunc[1];
7089 blendfunc1 = GL_ONE;
7090 blendfunc2 = GL_ZERO;
7092 depthmask = !(t->currentmaterialflags & MATERIALFLAG_BLENDED);
7093 if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
7095 // basic lit geometry
7096 R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE, t->basetexture, &t->currenttexmatrix, 2, 2, 2, t->currentalpha);
7097 // add pants/shirt if needed
7098 if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7099 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);
7100 if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7101 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);
7105 // basic lit geometry
7106 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);
7107 // add pants/shirt if needed
7108 if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7109 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);
7110 if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7111 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);
7112 // now add ambient passes if needed
7113 if (VectorLength2(t->render_lightmap_ambient) >= (1.0f/1048576.0f))
7115 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);
7116 if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7117 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);
7118 if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7119 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);
7122 if (t->glowtexture != NULL && !gl_lightmaps.integer)
7123 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);
7124 if (r_refdef.fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD))
7126 // if this is opaque use alpha blend which will darken the earlier
7129 // if this is an alpha blended material, all the earlier passes
7130 // were darkened by fog already, so we only need to add the fog
7131 // color ontop through the fog mask texture
7133 // if this is an additive blended material, all the earlier passes
7134 // were darkened by fog already, and we should not add fog color
7135 // (because the background was not darkened, there is no fog color
7136 // that was lost behind it).
7137 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);
7144 rsurfacestate_t rsurface;
7146 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
7148 dp_model_t *model = ent->model;
7149 //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
7151 rsurface.entity = (entity_render_t *)ent;
7152 rsurface.skeleton = ent->skeleton;
7153 memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
7154 rsurface.ent_skinnum = ent->skinnum;
7155 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;
7156 rsurface.ent_flags = ent->flags;
7157 if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
7158 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
7159 rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
7160 rsurface.matrix = ent->matrix;
7161 rsurface.inversematrix = ent->inversematrix;
7162 rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7163 rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7164 R_EntityMatrix(&rsurface.matrix);
7165 Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7166 Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7167 rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
7168 rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7169 rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7170 rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7171 memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
7172 rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
7173 rsurface.basepolygonfactor = r_refdef.polygonfactor;
7174 rsurface.basepolygonoffset = r_refdef.polygonoffset;
7175 if (ent->model->brush.submodel && !prepass)
7177 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
7178 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
7180 // if the animcache code decided it should use the shader path, skip the deform step
7181 rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
7182 rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
7183 rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
7184 rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
7185 rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
7186 if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
7188 if (ent->animcache_vertex3f)
7190 r_refdef.stats[r_stat_batch_entitycache_count]++;
7191 r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
7192 r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
7193 r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
7194 rsurface.modelvertex3f = ent->animcache_vertex3f;
7195 rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
7196 rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
7197 rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
7198 rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
7199 rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
7200 rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
7201 rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
7202 rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
7203 rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
7204 rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
7205 rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
7206 rsurface.modelvertexmesh = ent->animcache_vertexmesh;
7207 rsurface.modelvertexmesh_vertexbuffer = ent->animcache_vertexmesh_vertexbuffer;
7208 rsurface.modelvertexmesh_bufferoffset = ent->animcache_vertexmesh_bufferoffset;
7210 else if (wanttangents)
7212 r_refdef.stats[r_stat_batch_entityanimate_count]++;
7213 r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7214 r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7215 r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7216 rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7217 rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7218 rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7219 rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7220 model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
7221 rsurface.modelvertexmesh = NULL;
7222 rsurface.modelvertexmesh_vertexbuffer = NULL;
7223 rsurface.modelvertexmesh_bufferoffset = 0;
7224 rsurface.modelvertex3f_vertexbuffer = NULL;
7225 rsurface.modelvertex3f_bufferoffset = 0;
7226 rsurface.modelvertex3f_vertexbuffer = 0;
7227 rsurface.modelvertex3f_bufferoffset = 0;
7228 rsurface.modelsvector3f_vertexbuffer = 0;
7229 rsurface.modelsvector3f_bufferoffset = 0;
7230 rsurface.modeltvector3f_vertexbuffer = 0;
7231 rsurface.modeltvector3f_bufferoffset = 0;
7232 rsurface.modelnormal3f_vertexbuffer = 0;
7233 rsurface.modelnormal3f_bufferoffset = 0;
7235 else if (wantnormals)
7237 r_refdef.stats[r_stat_batch_entityanimate_count]++;
7238 r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7239 r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7240 r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7241 rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7242 rsurface.modelsvector3f = NULL;
7243 rsurface.modeltvector3f = NULL;
7244 rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7245 model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
7246 rsurface.modelvertexmesh = NULL;
7247 rsurface.modelvertexmesh_vertexbuffer = NULL;
7248 rsurface.modelvertexmesh_bufferoffset = 0;
7249 rsurface.modelvertex3f_vertexbuffer = NULL;
7250 rsurface.modelvertex3f_bufferoffset = 0;
7251 rsurface.modelvertex3f_vertexbuffer = 0;
7252 rsurface.modelvertex3f_bufferoffset = 0;
7253 rsurface.modelsvector3f_vertexbuffer = 0;
7254 rsurface.modelsvector3f_bufferoffset = 0;
7255 rsurface.modeltvector3f_vertexbuffer = 0;
7256 rsurface.modeltvector3f_bufferoffset = 0;
7257 rsurface.modelnormal3f_vertexbuffer = 0;
7258 rsurface.modelnormal3f_bufferoffset = 0;
7262 r_refdef.stats[r_stat_batch_entityanimate_count]++;
7263 r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7264 r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7265 r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7266 rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7267 rsurface.modelsvector3f = NULL;
7268 rsurface.modeltvector3f = NULL;
7269 rsurface.modelnormal3f = NULL;
7270 model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7271 rsurface.modelvertexmesh = NULL;
7272 rsurface.modelvertexmesh_vertexbuffer = NULL;
7273 rsurface.modelvertexmesh_bufferoffset = 0;
7274 rsurface.modelvertex3f_vertexbuffer = NULL;
7275 rsurface.modelvertex3f_bufferoffset = 0;
7276 rsurface.modelvertex3f_vertexbuffer = 0;
7277 rsurface.modelvertex3f_bufferoffset = 0;
7278 rsurface.modelsvector3f_vertexbuffer = 0;
7279 rsurface.modelsvector3f_bufferoffset = 0;
7280 rsurface.modeltvector3f_vertexbuffer = 0;
7281 rsurface.modeltvector3f_bufferoffset = 0;
7282 rsurface.modelnormal3f_vertexbuffer = 0;
7283 rsurface.modelnormal3f_bufferoffset = 0;
7285 rsurface.modelgeneratedvertex = true;
7289 if (rsurface.entityskeletaltransform3x4)
7291 r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7292 r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7293 r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7294 r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7298 r_refdef.stats[r_stat_batch_entitystatic_count]++;
7299 r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7300 r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7301 r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7303 rsurface.modelvertex3f = model->surfmesh.data_vertex3f;
7304 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7305 rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
7306 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7307 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7308 rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f;
7309 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7310 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7311 rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f;
7312 rsurface.modelnormal3f = model->surfmesh.data_normal3f;
7313 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7314 rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f;
7315 rsurface.modelvertexmesh = model->surfmesh.data_vertexmesh;
7316 rsurface.modelvertexmesh_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7317 rsurface.modelvertexmesh_bufferoffset = model->surfmesh.vbooffset_vertex3f;
7318 rsurface.modelgeneratedvertex = false;
7320 rsurface.modellightmapcolor4f = model->surfmesh.data_lightmapcolor4f;
7321 rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7322 rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f;
7323 rsurface.modeltexcoordtexture2f = model->surfmesh.data_texcoordtexture2f;
7324 rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7325 rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f;
7326 rsurface.modeltexcoordlightmap2f = model->surfmesh.data_texcoordlightmap2f;
7327 rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7328 rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
7329 rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7330 rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7331 rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.vbooffset_skeletalindex4ub;
7332 rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7333 rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7334 rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.vbooffset_skeletalweight4ub;
7335 rsurface.modelelement3i = model->surfmesh.data_element3i;
7336 rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7337 rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7338 rsurface.modelelement3s = model->surfmesh.data_element3s;
7339 rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7340 rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7341 rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7342 rsurface.modelnumvertices = model->surfmesh.num_vertices;
7343 rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7344 rsurface.modelsurfaces = model->data_surfaces;
7345 rsurface.batchgeneratedvertex = false;
7346 rsurface.batchfirstvertex = 0;
7347 rsurface.batchnumvertices = 0;
7348 rsurface.batchfirsttriangle = 0;
7349 rsurface.batchnumtriangles = 0;
7350 rsurface.batchvertex3f = NULL;
7351 rsurface.batchvertex3f_vertexbuffer = NULL;
7352 rsurface.batchvertex3f_bufferoffset = 0;
7353 rsurface.batchsvector3f = NULL;
7354 rsurface.batchsvector3f_vertexbuffer = NULL;
7355 rsurface.batchsvector3f_bufferoffset = 0;
7356 rsurface.batchtvector3f = NULL;
7357 rsurface.batchtvector3f_vertexbuffer = NULL;
7358 rsurface.batchtvector3f_bufferoffset = 0;
7359 rsurface.batchnormal3f = NULL;
7360 rsurface.batchnormal3f_vertexbuffer = NULL;
7361 rsurface.batchnormal3f_bufferoffset = 0;
7362 rsurface.batchlightmapcolor4f = NULL;
7363 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7364 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7365 rsurface.batchtexcoordtexture2f = NULL;
7366 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7367 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7368 rsurface.batchtexcoordlightmap2f = NULL;
7369 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7370 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7371 rsurface.batchskeletalindex4ub = NULL;
7372 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7373 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7374 rsurface.batchskeletalweight4ub = NULL;
7375 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7376 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7377 rsurface.batchvertexmesh = NULL;
7378 rsurface.batchvertexmesh_vertexbuffer = NULL;
7379 rsurface.batchvertexmesh_bufferoffset = 0;
7380 rsurface.batchelement3i = NULL;
7381 rsurface.batchelement3i_indexbuffer = NULL;
7382 rsurface.batchelement3i_bufferoffset = 0;
7383 rsurface.batchelement3s = NULL;
7384 rsurface.batchelement3s_indexbuffer = NULL;
7385 rsurface.batchelement3s_bufferoffset = 0;
7386 rsurface.forcecurrenttextureupdate = false;
7389 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)
7391 rsurface.entity = r_refdef.scene.worldentity;
7392 rsurface.skeleton = NULL;
7393 rsurface.ent_skinnum = 0;
7394 rsurface.ent_qwskin = -1;
7395 rsurface.ent_flags = entflags;
7396 rsurface.shadertime = r_refdef.scene.time - shadertime;
7397 rsurface.modelnumvertices = numvertices;
7398 rsurface.modelnumtriangles = numtriangles;
7399 rsurface.matrix = *matrix;
7400 rsurface.inversematrix = *inversematrix;
7401 rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7402 rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7403 R_EntityMatrix(&rsurface.matrix);
7404 Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7405 Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7406 rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7407 rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7408 rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7409 rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7410 memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7411 rsurface.frameblend[0].lerp = 1;
7412 rsurface.ent_alttextures = false;
7413 rsurface.basepolygonfactor = r_refdef.polygonfactor;
7414 rsurface.basepolygonoffset = r_refdef.polygonoffset;
7415 rsurface.entityskeletaltransform3x4 = NULL;
7416 rsurface.entityskeletaltransform3x4buffer = NULL;
7417 rsurface.entityskeletaltransform3x4offset = 0;
7418 rsurface.entityskeletaltransform3x4size = 0;
7419 rsurface.entityskeletalnumtransforms = 0;
7420 r_refdef.stats[r_stat_batch_entitycustom_count]++;
7421 r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7422 r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7423 r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7426 rsurface.modelvertex3f = (float *)vertex3f;
7427 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7428 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7429 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7431 else if (wantnormals)
7433 rsurface.modelvertex3f = (float *)vertex3f;
7434 rsurface.modelsvector3f = NULL;
7435 rsurface.modeltvector3f = NULL;
7436 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7440 rsurface.modelvertex3f = (float *)vertex3f;
7441 rsurface.modelsvector3f = NULL;
7442 rsurface.modeltvector3f = NULL;
7443 rsurface.modelnormal3f = NULL;
7445 rsurface.modelvertexmesh = NULL;
7446 rsurface.modelvertexmesh_vertexbuffer = NULL;
7447 rsurface.modelvertexmesh_bufferoffset = 0;
7448 rsurface.modelvertex3f_vertexbuffer = 0;
7449 rsurface.modelvertex3f_bufferoffset = 0;
7450 rsurface.modelsvector3f_vertexbuffer = 0;
7451 rsurface.modelsvector3f_bufferoffset = 0;
7452 rsurface.modeltvector3f_vertexbuffer = 0;
7453 rsurface.modeltvector3f_bufferoffset = 0;
7454 rsurface.modelnormal3f_vertexbuffer = 0;
7455 rsurface.modelnormal3f_bufferoffset = 0;
7456 rsurface.modelgeneratedvertex = true;
7457 rsurface.modellightmapcolor4f = (float *)color4f;
7458 rsurface.modellightmapcolor4f_vertexbuffer = 0;
7459 rsurface.modellightmapcolor4f_bufferoffset = 0;
7460 rsurface.modeltexcoordtexture2f = (float *)texcoord2f;
7461 rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7462 rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7463 rsurface.modeltexcoordlightmap2f = NULL;
7464 rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7465 rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7466 rsurface.modelskeletalindex4ub = NULL;
7467 rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7468 rsurface.modelskeletalindex4ub_bufferoffset = 0;
7469 rsurface.modelskeletalweight4ub = NULL;
7470 rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7471 rsurface.modelskeletalweight4ub_bufferoffset = 0;
7472 rsurface.modelelement3i = (int *)element3i;
7473 rsurface.modelelement3i_indexbuffer = NULL;
7474 rsurface.modelelement3i_bufferoffset = 0;
7475 rsurface.modelelement3s = (unsigned short *)element3s;
7476 rsurface.modelelement3s_indexbuffer = NULL;
7477 rsurface.modelelement3s_bufferoffset = 0;
7478 rsurface.modellightmapoffsets = NULL;
7479 rsurface.modelsurfaces = NULL;
7480 rsurface.batchgeneratedvertex = false;
7481 rsurface.batchfirstvertex = 0;
7482 rsurface.batchnumvertices = 0;
7483 rsurface.batchfirsttriangle = 0;
7484 rsurface.batchnumtriangles = 0;
7485 rsurface.batchvertex3f = NULL;
7486 rsurface.batchvertex3f_vertexbuffer = NULL;
7487 rsurface.batchvertex3f_bufferoffset = 0;
7488 rsurface.batchsvector3f = NULL;
7489 rsurface.batchsvector3f_vertexbuffer = NULL;
7490 rsurface.batchsvector3f_bufferoffset = 0;
7491 rsurface.batchtvector3f = NULL;
7492 rsurface.batchtvector3f_vertexbuffer = NULL;
7493 rsurface.batchtvector3f_bufferoffset = 0;
7494 rsurface.batchnormal3f = NULL;
7495 rsurface.batchnormal3f_vertexbuffer = NULL;
7496 rsurface.batchnormal3f_bufferoffset = 0;
7497 rsurface.batchlightmapcolor4f = NULL;
7498 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7499 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7500 rsurface.batchtexcoordtexture2f = NULL;
7501 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7502 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7503 rsurface.batchtexcoordlightmap2f = NULL;
7504 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7505 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7506 rsurface.batchskeletalindex4ub = NULL;
7507 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7508 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7509 rsurface.batchskeletalweight4ub = NULL;
7510 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7511 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7512 rsurface.batchvertexmesh = NULL;
7513 rsurface.batchvertexmesh_vertexbuffer = NULL;
7514 rsurface.batchvertexmesh_bufferoffset = 0;
7515 rsurface.batchelement3i = NULL;
7516 rsurface.batchelement3i_indexbuffer = NULL;
7517 rsurface.batchelement3i_bufferoffset = 0;
7518 rsurface.batchelement3s = NULL;
7519 rsurface.batchelement3s_indexbuffer = NULL;
7520 rsurface.batchelement3s_bufferoffset = 0;
7521 rsurface.forcecurrenttextureupdate = true;
7523 if (rsurface.modelnumvertices && rsurface.modelelement3i)
7525 if ((wantnormals || wanttangents) && !normal3f)
7527 rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7528 Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7530 if (wanttangents && !svector3f)
7532 rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7533 rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7534 Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7539 float RSurf_FogPoint(const float *v)
7541 // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7542 float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7543 float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7544 float FogHeightFade = r_refdef.fogheightfade;
7546 unsigned int fogmasktableindex;
7547 if (r_refdef.fogplaneviewabove)
7548 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7550 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7551 fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7552 return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7555 float RSurf_FogVertex(const float *v)
7557 // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7558 float FogPlaneViewDist = rsurface.fogplaneviewdist;
7559 float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7560 float FogHeightFade = rsurface.fogheightfade;
7562 unsigned int fogmasktableindex;
7563 if (r_refdef.fogplaneviewabove)
7564 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7566 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7567 fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7568 return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7571 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7574 for (i = 0;i < numelements;i++)
7575 outelement3i[i] = inelement3i[i] + adjust;
7578 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7579 extern cvar_t gl_vbo;
7580 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7588 int surfacefirsttriangle;
7589 int surfacenumtriangles;
7590 int surfacefirstvertex;
7591 int surfaceendvertex;
7592 int surfacenumvertices;
7593 int batchnumsurfaces = texturenumsurfaces;
7594 int batchnumvertices;
7595 int batchnumtriangles;
7599 qboolean dynamicvertex;
7602 float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7605 q3shaderinfo_deform_t *deform;
7606 const msurface_t *surface, *firstsurface;
7607 r_vertexmesh_t *vertexmesh;
7608 if (!texturenumsurfaces)
7610 // find vertex range of this surface batch
7612 firstsurface = texturesurfacelist[0];
7613 firsttriangle = firstsurface->num_firsttriangle;
7614 batchnumvertices = 0;
7615 batchnumtriangles = 0;
7616 firstvertex = endvertex = firstsurface->num_firstvertex;
7617 for (i = 0;i < texturenumsurfaces;i++)
7619 surface = texturesurfacelist[i];
7620 if (surface != firstsurface + i)
7622 surfacefirstvertex = surface->num_firstvertex;
7623 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7624 surfacenumvertices = surface->num_vertices;
7625 surfacenumtriangles = surface->num_triangles;
7626 if (firstvertex > surfacefirstvertex)
7627 firstvertex = surfacefirstvertex;
7628 if (endvertex < surfaceendvertex)
7629 endvertex = surfaceendvertex;
7630 batchnumvertices += surfacenumvertices;
7631 batchnumtriangles += surfacenumtriangles;
7634 r_refdef.stats[r_stat_batch_batches]++;
7636 r_refdef.stats[r_stat_batch_withgaps]++;
7637 r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7638 r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7639 r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7641 // we now know the vertex range used, and if there are any gaps in it
7642 rsurface.batchfirstvertex = firstvertex;
7643 rsurface.batchnumvertices = endvertex - firstvertex;
7644 rsurface.batchfirsttriangle = firsttriangle;
7645 rsurface.batchnumtriangles = batchnumtriangles;
7647 // this variable holds flags for which properties have been updated that
7648 // may require regenerating vertexmesh array...
7651 // check if any dynamic vertex processing must occur
7652 dynamicvertex = false;
7654 // a cvar to force the dynamic vertex path to be taken, for debugging
7655 if (r_batch_debugdynamicvertexpath.integer)
7659 r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7660 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7661 r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7662 r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7664 dynamicvertex = true;
7667 // if there is a chance of animated vertex colors, it's a dynamic batch
7668 if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo)
7672 r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7673 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7674 r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7675 r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7677 dynamicvertex = true;
7678 needsupdate |= BATCHNEED_VERTEXMESH_VERTEXCOLOR;
7681 for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7683 switch (deform->deform)
7686 case Q3DEFORM_PROJECTIONSHADOW:
7687 case Q3DEFORM_TEXT0:
7688 case Q3DEFORM_TEXT1:
7689 case Q3DEFORM_TEXT2:
7690 case Q3DEFORM_TEXT3:
7691 case Q3DEFORM_TEXT4:
7692 case Q3DEFORM_TEXT5:
7693 case Q3DEFORM_TEXT6:
7694 case Q3DEFORM_TEXT7:
7697 case Q3DEFORM_AUTOSPRITE:
7700 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7701 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7702 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7703 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7705 dynamicvertex = true;
7706 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7707 needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7709 case Q3DEFORM_AUTOSPRITE2:
7712 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7713 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7714 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7715 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7717 dynamicvertex = true;
7718 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7719 needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7721 case Q3DEFORM_NORMAL:
7724 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7725 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7726 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7727 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7729 dynamicvertex = true;
7730 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7731 needsupdate |= BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7734 if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7735 break; // if wavefunc is a nop, ignore this transform
7738 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7739 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7740 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7741 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7743 dynamicvertex = true;
7744 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7745 needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7747 case Q3DEFORM_BULGE:
7750 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7751 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7752 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7753 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7755 dynamicvertex = true;
7756 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7757 needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7760 if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7761 break; // if wavefunc is a nop, ignore this transform
7764 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7765 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7766 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7767 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7769 dynamicvertex = true;
7770 batchneed |= BATCHNEED_ARRAY_VERTEX;
7771 needsupdate |= BATCHNEED_VERTEXMESH_VERTEX;
7775 if (rsurface.texture->materialshaderpass)
7777 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7780 case Q3TCGEN_TEXTURE:
7782 case Q3TCGEN_LIGHTMAP:
7785 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7786 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7787 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7788 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7790 dynamicvertex = true;
7791 batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7792 needsupdate |= BATCHNEED_VERTEXMESH_LIGHTMAP;
7794 case Q3TCGEN_VECTOR:
7797 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7798 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7799 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7800 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7802 dynamicvertex = true;
7803 batchneed |= BATCHNEED_ARRAY_VERTEX;
7804 needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
7806 case Q3TCGEN_ENVIRONMENT:
7809 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7810 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7811 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7812 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7814 dynamicvertex = true;
7815 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7816 needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
7819 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7823 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7824 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7825 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7826 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7828 dynamicvertex = true;
7829 batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7830 needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
7834 if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)))
7838 r_refdef.stats[r_stat_batch_dynamic_batches_because_interleavedarrays] += 1;
7839 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_interleavedarrays] += batchnumsurfaces;
7840 r_refdef.stats[r_stat_batch_dynamic_vertices_because_interleavedarrays] += batchnumvertices;
7841 r_refdef.stats[r_stat_batch_dynamic_triangles_because_interleavedarrays] += batchnumtriangles;
7843 dynamicvertex = true;
7844 needsupdate |= (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP));
7847 // when the model data has no vertex buffer (dynamic mesh), we need to
7849 if (vid.useinterleavedarrays && !rsurface.modelvertexmesh_vertexbuffer)
7850 batchneed |= BATCHNEED_NOGAPS;
7852 // the caller can specify BATCHNEED_NOGAPS to force a batch with
7853 // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7854 // we ensure this by treating the vertex batch as dynamic...
7855 if ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0))
7859 r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7860 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7861 r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7862 r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7864 dynamicvertex = true;
7869 // when copying, we need to consider the regeneration of vertexmesh, any dependencies it may have must be set...
7870 if (batchneed & BATCHNEED_VERTEXMESH_VERTEX) batchneed |= BATCHNEED_ARRAY_VERTEX;
7871 if (batchneed & BATCHNEED_VERTEXMESH_NORMAL) batchneed |= BATCHNEED_ARRAY_NORMAL;
7872 if (batchneed & BATCHNEED_VERTEXMESH_VECTOR) batchneed |= BATCHNEED_ARRAY_VECTOR;
7873 if (batchneed & BATCHNEED_VERTEXMESH_VERTEXCOLOR) batchneed |= BATCHNEED_ARRAY_VERTEXCOLOR;
7874 if (batchneed & BATCHNEED_VERTEXMESH_TEXCOORD) batchneed |= BATCHNEED_ARRAY_TEXCOORD;
7875 if (batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP) batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7876 if (batchneed & BATCHNEED_VERTEXMESH_SKELETAL) batchneed |= BATCHNEED_ARRAY_SKELETAL;
7879 // if needsupdate, we have to do a dynamic vertex batch for sure
7880 if (needsupdate & batchneed)
7884 r_refdef.stats[r_stat_batch_dynamic_batches_because_derived] += 1;
7885 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_derived] += batchnumsurfaces;
7886 r_refdef.stats[r_stat_batch_dynamic_vertices_because_derived] += batchnumvertices;
7887 r_refdef.stats[r_stat_batch_dynamic_triangles_because_derived] += batchnumtriangles;
7889 dynamicvertex = true;
7892 // see if we need to build vertexmesh from arrays
7893 if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)))
7897 r_refdef.stats[r_stat_batch_dynamic_batches_because_interleavedarrays] += 1;
7898 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_interleavedarrays] += batchnumsurfaces;
7899 r_refdef.stats[r_stat_batch_dynamic_vertices_because_interleavedarrays] += batchnumvertices;
7900 r_refdef.stats[r_stat_batch_dynamic_triangles_because_interleavedarrays] += batchnumtriangles;
7902 dynamicvertex = true;
7905 // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7906 if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7907 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7909 rsurface.batchvertex3f = rsurface.modelvertex3f;
7910 rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7911 rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7912 rsurface.batchsvector3f = rsurface.modelsvector3f;
7913 rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7914 rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7915 rsurface.batchtvector3f = rsurface.modeltvector3f;
7916 rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7917 rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7918 rsurface.batchnormal3f = rsurface.modelnormal3f;
7919 rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7920 rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7921 rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7922 rsurface.batchlightmapcolor4f_vertexbuffer = rsurface.modellightmapcolor4f_vertexbuffer;
7923 rsurface.batchlightmapcolor4f_bufferoffset = rsurface.modellightmapcolor4f_bufferoffset;
7924 rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7925 rsurface.batchtexcoordtexture2f_vertexbuffer = rsurface.modeltexcoordtexture2f_vertexbuffer;
7926 rsurface.batchtexcoordtexture2f_bufferoffset = rsurface.modeltexcoordtexture2f_bufferoffset;
7927 rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7928 rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7929 rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7930 rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7931 rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7932 rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7933 rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7934 rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7935 rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7936 rsurface.batchvertexmesh = rsurface.modelvertexmesh;
7937 rsurface.batchvertexmesh_vertexbuffer = rsurface.modelvertexmesh_vertexbuffer;
7938 rsurface.batchvertexmesh_bufferoffset = rsurface.modelvertexmesh_bufferoffset;
7939 rsurface.batchelement3i = rsurface.modelelement3i;
7940 rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7941 rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7942 rsurface.batchelement3s = rsurface.modelelement3s;
7943 rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7944 rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7945 rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7946 rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7947 rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7948 rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7949 rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7951 // if any dynamic vertex processing has to occur in software, we copy the
7952 // entire surface list together before processing to rebase the vertices
7953 // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7955 // if any gaps exist and we do not have a static vertex buffer, we have to
7956 // copy the surface list together to avoid wasting upload bandwidth on the
7957 // vertices in the gaps.
7959 // if gaps exist and we have a static vertex buffer, we can choose whether
7960 // to combine the index buffer ranges into one dynamic index buffer or
7961 // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7963 // in many cases the batch is reduced to one draw call.
7965 rsurface.batchmultidraw = false;
7966 rsurface.batchmultidrawnumsurfaces = 0;
7967 rsurface.batchmultidrawsurfacelist = NULL;
7971 // static vertex data, just set pointers...
7972 rsurface.batchgeneratedvertex = false;
7973 // if there are gaps, we want to build a combined index buffer,
7974 // otherwise use the original static buffer with an appropriate offset
7977 r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7978 r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7979 r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7980 r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7981 if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7983 rsurface.batchmultidraw = true;
7984 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7985 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7988 // build a new triangle elements array for this batch
7989 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7990 rsurface.batchfirsttriangle = 0;
7992 for (i = 0;i < texturenumsurfaces;i++)
7994 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7995 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7996 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7997 numtriangles += surfacenumtriangles;
7999 rsurface.batchelement3i_indexbuffer = NULL;
8000 rsurface.batchelement3i_bufferoffset = 0;
8001 rsurface.batchelement3s = NULL;
8002 rsurface.batchelement3s_indexbuffer = NULL;
8003 rsurface.batchelement3s_bufferoffset = 0;
8004 if (endvertex <= 65536)
8006 // make a 16bit (unsigned short) index array if possible
8007 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
8008 for (i = 0;i < numtriangles*3;i++)
8009 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
8011 // upload buffer data for the copytriangles batch
8012 if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo)
8014 if (rsurface.batchelement3s)
8015 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
8016 else if (rsurface.batchelement3i)
8017 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
8022 r_refdef.stats[r_stat_batch_fast_batches] += 1;
8023 r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
8024 r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
8025 r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
8030 // something needs software processing, do it for real...
8031 // we only directly handle separate array data in this case and then
8032 // generate interleaved data if needed...
8033 rsurface.batchgeneratedvertex = true;
8034 r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
8035 r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
8036 r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
8037 r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
8039 // now copy the vertex data into a combined array and make an index array
8040 // (this is what Quake3 does all the time)
8041 // we also apply any skeletal animation here that would have been done in
8042 // the vertex shader, because most of the dynamic vertex animation cases
8043 // need actual vertex positions and normals
8044 //if (dynamicvertex)
8046 rsurface.batchvertexmesh = NULL;
8047 rsurface.batchvertexmesh_vertexbuffer = NULL;
8048 rsurface.batchvertexmesh_bufferoffset = 0;
8049 rsurface.batchvertex3f = NULL;
8050 rsurface.batchvertex3f_vertexbuffer = NULL;
8051 rsurface.batchvertex3f_bufferoffset = 0;
8052 rsurface.batchsvector3f = NULL;
8053 rsurface.batchsvector3f_vertexbuffer = NULL;
8054 rsurface.batchsvector3f_bufferoffset = 0;
8055 rsurface.batchtvector3f = NULL;
8056 rsurface.batchtvector3f_vertexbuffer = NULL;
8057 rsurface.batchtvector3f_bufferoffset = 0;
8058 rsurface.batchnormal3f = NULL;
8059 rsurface.batchnormal3f_vertexbuffer = NULL;
8060 rsurface.batchnormal3f_bufferoffset = 0;
8061 rsurface.batchlightmapcolor4f = NULL;
8062 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8063 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8064 rsurface.batchtexcoordtexture2f = NULL;
8065 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8066 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8067 rsurface.batchtexcoordlightmap2f = NULL;
8068 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
8069 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
8070 rsurface.batchskeletalindex4ub = NULL;
8071 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
8072 rsurface.batchskeletalindex4ub_bufferoffset = 0;
8073 rsurface.batchskeletalweight4ub = NULL;
8074 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
8075 rsurface.batchskeletalweight4ub_bufferoffset = 0;
8076 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
8077 rsurface.batchelement3i_indexbuffer = NULL;
8078 rsurface.batchelement3i_bufferoffset = 0;
8079 rsurface.batchelement3s = NULL;
8080 rsurface.batchelement3s_indexbuffer = NULL;
8081 rsurface.batchelement3s_bufferoffset = 0;
8082 rsurface.batchskeletaltransform3x4buffer = NULL;
8083 rsurface.batchskeletaltransform3x4offset = 0;
8084 rsurface.batchskeletaltransform3x4size = 0;
8085 // we'll only be setting up certain arrays as needed
8086 if (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP))
8087 rsurface.batchvertexmesh = (r_vertexmesh_t *)R_FrameData_Alloc(batchnumvertices * sizeof(r_vertexmesh_t));
8088 if (batchneed & BATCHNEED_ARRAY_VERTEX)
8089 rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8090 if (batchneed & BATCHNEED_ARRAY_NORMAL)
8091 rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8092 if (batchneed & BATCHNEED_ARRAY_VECTOR)
8094 rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8095 rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8097 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
8098 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8099 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
8100 rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8101 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
8102 rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8103 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
8105 rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
8106 rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
8110 for (i = 0;i < texturenumsurfaces;i++)
8112 surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
8113 surfacenumvertices = texturesurfacelist[i]->num_vertices;
8114 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
8115 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
8116 // copy only the data requested
8117 if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)) && rsurface.modelvertexmesh)
8118 memcpy(rsurface.batchvertexmesh + numvertices, rsurface.modelvertexmesh + surfacefirstvertex, surfacenumvertices * sizeof(rsurface.batchvertexmesh[0]));
8119 if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
8121 if (batchneed & BATCHNEED_ARRAY_VERTEX)
8123 if (rsurface.batchvertex3f)
8124 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8126 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8128 if (batchneed & BATCHNEED_ARRAY_NORMAL)
8130 if (rsurface.modelnormal3f)
8131 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8133 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8135 if (batchneed & BATCHNEED_ARRAY_VECTOR)
8137 if (rsurface.modelsvector3f)
8139 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8140 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8144 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8145 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8148 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
8150 if (rsurface.modellightmapcolor4f)
8151 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
8153 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
8155 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
8157 if (rsurface.modeltexcoordtexture2f)
8158 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
8160 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
8162 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
8164 if (rsurface.modeltexcoordlightmap2f)
8165 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
8167 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
8169 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
8171 if (rsurface.modelskeletalindex4ub)
8173 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
8174 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
8178 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
8179 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
8180 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
8181 for (j = 0;j < surfacenumvertices;j++)
8186 RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
8187 numvertices += surfacenumvertices;
8188 numtriangles += surfacenumtriangles;
8191 // generate a 16bit index array as well if possible
8192 // (in general, dynamic batches fit)
8193 if (numvertices <= 65536)
8195 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
8196 for (i = 0;i < numtriangles*3;i++)
8197 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
8200 // since we've copied everything, the batch now starts at 0
8201 rsurface.batchfirstvertex = 0;
8202 rsurface.batchnumvertices = batchnumvertices;
8203 rsurface.batchfirsttriangle = 0;
8204 rsurface.batchnumtriangles = batchnumtriangles;
8207 // apply skeletal animation that would have been done in the vertex shader
8208 if (rsurface.batchskeletaltransform3x4)
8210 const unsigned char *si;
8211 const unsigned char *sw;
8213 const float *b = rsurface.batchskeletaltransform3x4;
8214 float *vp, *vs, *vt, *vn;
8216 float m[3][4], n[3][4];
8217 float tp[3], ts[3], tt[3], tn[3];
8218 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
8219 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
8220 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
8221 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
8222 si = rsurface.batchskeletalindex4ub;
8223 sw = rsurface.batchskeletalweight4ub;
8224 vp = rsurface.batchvertex3f;
8225 vs = rsurface.batchsvector3f;
8226 vt = rsurface.batchtvector3f;
8227 vn = rsurface.batchnormal3f;
8228 memset(m[0], 0, sizeof(m));
8229 memset(n[0], 0, sizeof(n));
8230 for (i = 0;i < batchnumvertices;i++)
8232 t[0] = b + si[0]*12;
8235 // common case - only one matrix
8249 else if (sw[2] + sw[3])
8252 t[1] = b + si[1]*12;
8253 t[2] = b + si[2]*12;
8254 t[3] = b + si[3]*12;
8255 w[0] = sw[0] * (1.0f / 255.0f);
8256 w[1] = sw[1] * (1.0f / 255.0f);
8257 w[2] = sw[2] * (1.0f / 255.0f);
8258 w[3] = sw[3] * (1.0f / 255.0f);
8259 // blend the matrices
8260 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
8261 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
8262 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
8263 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
8264 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
8265 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
8266 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
8267 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
8268 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
8269 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
8270 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
8271 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
8276 t[1] = b + si[1]*12;
8277 w[0] = sw[0] * (1.0f / 255.0f);
8278 w[1] = sw[1] * (1.0f / 255.0f);
8279 // blend the matrices
8280 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
8281 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
8282 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
8283 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
8284 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
8285 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
8286 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
8287 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
8288 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
8289 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
8290 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
8291 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
8295 // modify the vertex
8297 vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
8298 vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
8299 vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
8303 // the normal transformation matrix is a set of cross products...
8304 CrossProduct(m[1], m[2], n[0]);
8305 CrossProduct(m[2], m[0], n[1]);
8306 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8308 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8309 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8310 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8311 VectorNormalize(vn);
8316 vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8317 vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8318 vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8319 VectorNormalize(vs);
8322 vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8323 vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8324 vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8325 VectorNormalize(vt);
8330 rsurface.batchskeletaltransform3x4 = NULL;
8331 rsurface.batchskeletalnumtransforms = 0;
8334 // q1bsp surfaces rendered in vertex color mode have to have colors
8335 // calculated based on lightstyles
8336 if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo)
8338 // generate color arrays for the surfaces in this list
8343 const unsigned char *lm;
8344 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8345 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8346 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8348 for (i = 0;i < texturenumsurfaces;i++)
8350 surface = texturesurfacelist[i];
8351 offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8352 surfacenumvertices = surface->num_vertices;
8353 if (surface->lightmapinfo->samples)
8355 for (j = 0;j < surfacenumvertices;j++)
8357 lm = surface->lightmapinfo->samples + offsets[j];
8358 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8359 VectorScale(lm, scale, c);
8360 if (surface->lightmapinfo->styles[1] != 255)
8362 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8364 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8365 VectorMA(c, scale, lm, c);
8366 if (surface->lightmapinfo->styles[2] != 255)
8369 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8370 VectorMA(c, scale, lm, c);
8371 if (surface->lightmapinfo->styles[3] != 255)
8374 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8375 VectorMA(c, scale, lm, c);
8382 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);
8388 for (j = 0;j < surfacenumvertices;j++)
8390 Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8397 // if vertices are deformed (sprite flares and things in maps, possibly
8398 // water waves, bulges and other deformations), modify the copied vertices
8400 for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8403 switch (deform->deform)
8406 case Q3DEFORM_PROJECTIONSHADOW:
8407 case Q3DEFORM_TEXT0:
8408 case Q3DEFORM_TEXT1:
8409 case Q3DEFORM_TEXT2:
8410 case Q3DEFORM_TEXT3:
8411 case Q3DEFORM_TEXT4:
8412 case Q3DEFORM_TEXT5:
8413 case Q3DEFORM_TEXT6:
8414 case Q3DEFORM_TEXT7:
8417 case Q3DEFORM_AUTOSPRITE:
8418 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8419 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8420 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8421 VectorNormalize(newforward);
8422 VectorNormalize(newright);
8423 VectorNormalize(newup);
8424 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8425 // rsurface.batchvertex3f_vertexbuffer = NULL;
8426 // rsurface.batchvertex3f_bufferoffset = 0;
8427 // rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8428 // rsurface.batchsvector3f_vertexbuffer = NULL;
8429 // rsurface.batchsvector3f_bufferoffset = 0;
8430 // rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8431 // rsurface.batchtvector3f_vertexbuffer = NULL;
8432 // rsurface.batchtvector3f_bufferoffset = 0;
8433 // rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8434 // rsurface.batchnormal3f_vertexbuffer = NULL;
8435 // rsurface.batchnormal3f_bufferoffset = 0;
8436 // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8437 if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8438 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8439 if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8440 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);
8441 // a single autosprite surface can contain multiple sprites...
8442 for (j = 0;j < batchnumvertices - 3;j += 4)
8444 VectorClear(center);
8445 for (i = 0;i < 4;i++)
8446 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8447 VectorScale(center, 0.25f, center);
8448 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8449 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8450 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8451 for (i = 0;i < 4;i++)
8453 VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8454 VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8457 // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8458 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8459 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);
8461 case Q3DEFORM_AUTOSPRITE2:
8462 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8463 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8464 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8465 VectorNormalize(newforward);
8466 VectorNormalize(newright);
8467 VectorNormalize(newup);
8468 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8469 // rsurface.batchvertex3f_vertexbuffer = NULL;
8470 // rsurface.batchvertex3f_bufferoffset = 0;
8472 const float *v1, *v2;
8482 memset(shortest, 0, sizeof(shortest));
8483 // a single autosprite surface can contain multiple sprites...
8484 for (j = 0;j < batchnumvertices - 3;j += 4)
8486 VectorClear(center);
8487 for (i = 0;i < 4;i++)
8488 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8489 VectorScale(center, 0.25f, center);
8490 // find the two shortest edges, then use them to define the
8491 // axis vectors for rotating around the central axis
8492 for (i = 0;i < 6;i++)
8494 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8495 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8496 l = VectorDistance2(v1, v2);
8497 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8499 l += (1.0f / 1024.0f);
8500 if (shortest[0].length2 > l || i == 0)
8502 shortest[1] = shortest[0];
8503 shortest[0].length2 = l;
8504 shortest[0].v1 = v1;
8505 shortest[0].v2 = v2;
8507 else if (shortest[1].length2 > l || i == 1)
8509 shortest[1].length2 = l;
8510 shortest[1].v1 = v1;
8511 shortest[1].v2 = v2;
8514 VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8515 VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8516 // this calculates the right vector from the shortest edge
8517 // and the up vector from the edge midpoints
8518 VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8519 VectorNormalize(right);
8520 VectorSubtract(end, start, up);
8521 VectorNormalize(up);
8522 // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8523 VectorSubtract(rsurface.localvieworigin, center, forward);
8524 //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8525 VectorNegate(forward, forward);
8526 VectorReflect(forward, 0, up, forward);
8527 VectorNormalize(forward);
8528 CrossProduct(up, forward, newright);
8529 VectorNormalize(newright);
8530 // rotate the quad around the up axis vector, this is made
8531 // especially easy by the fact we know the quad is flat,
8532 // so we only have to subtract the center position and
8533 // measure distance along the right vector, and then
8534 // multiply that by the newright vector and add back the
8536 // we also need to subtract the old position to undo the
8537 // displacement from the center, which we do with a
8538 // DotProduct, the subtraction/addition of center is also
8539 // optimized into DotProducts here
8540 l = DotProduct(right, center);
8541 for (i = 0;i < 4;i++)
8543 v1 = rsurface.batchvertex3f + 3*(j+i);
8544 f = DotProduct(right, v1) - l;
8545 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8549 if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8551 // rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8552 // rsurface.batchnormal3f_vertexbuffer = NULL;
8553 // rsurface.batchnormal3f_bufferoffset = 0;
8554 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8556 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8558 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8559 // rsurface.batchsvector3f_vertexbuffer = NULL;
8560 // rsurface.batchsvector3f_bufferoffset = 0;
8561 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8562 // rsurface.batchtvector3f_vertexbuffer = NULL;
8563 // rsurface.batchtvector3f_bufferoffset = 0;
8564 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);
8567 case Q3DEFORM_NORMAL:
8568 // deform the normals to make reflections wavey
8569 rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8570 rsurface.batchnormal3f_vertexbuffer = NULL;
8571 rsurface.batchnormal3f_bufferoffset = 0;
8572 for (j = 0;j < batchnumvertices;j++)
8575 float *normal = rsurface.batchnormal3f + 3*j;
8576 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8577 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f( vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8578 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8579 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8580 VectorNormalize(normal);
8582 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8584 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8585 // rsurface.batchsvector3f_vertexbuffer = NULL;
8586 // rsurface.batchsvector3f_bufferoffset = 0;
8587 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8588 // rsurface.batchtvector3f_vertexbuffer = NULL;
8589 // rsurface.batchtvector3f_bufferoffset = 0;
8590 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);
8594 // deform vertex array to make wavey water and flags and such
8595 waveparms[0] = deform->waveparms[0];
8596 waveparms[1] = deform->waveparms[1];
8597 waveparms[2] = deform->waveparms[2];
8598 waveparms[3] = deform->waveparms[3];
8599 if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8600 break; // if wavefunc is a nop, don't make a dynamic vertex array
8601 // this is how a divisor of vertex influence on deformation
8602 animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8603 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8604 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8605 // rsurface.batchvertex3f_vertexbuffer = NULL;
8606 // rsurface.batchvertex3f_bufferoffset = 0;
8607 // rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8608 // rsurface.batchnormal3f_vertexbuffer = NULL;
8609 // rsurface.batchnormal3f_bufferoffset = 0;
8610 for (j = 0;j < batchnumvertices;j++)
8612 // if the wavefunc depends on time, evaluate it per-vertex
8615 waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8616 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8618 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8620 // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8621 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8622 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8624 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8625 // rsurface.batchsvector3f_vertexbuffer = NULL;
8626 // rsurface.batchsvector3f_bufferoffset = 0;
8627 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8628 // rsurface.batchtvector3f_vertexbuffer = NULL;
8629 // rsurface.batchtvector3f_bufferoffset = 0;
8630 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);
8633 case Q3DEFORM_BULGE:
8634 // deform vertex array to make the surface have moving bulges
8635 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8636 // rsurface.batchvertex3f_vertexbuffer = NULL;
8637 // rsurface.batchvertex3f_bufferoffset = 0;
8638 // rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8639 // rsurface.batchnormal3f_vertexbuffer = NULL;
8640 // rsurface.batchnormal3f_bufferoffset = 0;
8641 for (j = 0;j < batchnumvertices;j++)
8643 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8644 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8646 // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8647 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8648 if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8650 // rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8651 // rsurface.batchsvector3f_vertexbuffer = NULL;
8652 // rsurface.batchsvector3f_bufferoffset = 0;
8653 // rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8654 // rsurface.batchtvector3f_vertexbuffer = NULL;
8655 // rsurface.batchtvector3f_bufferoffset = 0;
8656 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);
8660 // deform vertex array
8661 if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8662 break; // if wavefunc is a nop, don't make a dynamic vertex array
8663 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8664 VectorScale(deform->parms, scale, waveparms);
8665 // rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8666 // rsurface.batchvertex3f_vertexbuffer = NULL;
8667 // rsurface.batchvertex3f_bufferoffset = 0;
8668 for (j = 0;j < batchnumvertices;j++)
8669 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8674 if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8676 // generate texcoords based on the chosen texcoord source
8677 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8680 case Q3TCGEN_TEXTURE:
8682 case Q3TCGEN_LIGHTMAP:
8683 // rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8684 // rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8685 // rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8686 if (rsurface.batchtexcoordlightmap2f)
8687 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8689 case Q3TCGEN_VECTOR:
8690 // rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8691 // rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8692 // rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8693 for (j = 0;j < batchnumvertices;j++)
8695 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8696 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8699 case Q3TCGEN_ENVIRONMENT:
8700 // make environment reflections using a spheremap
8701 rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8702 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8703 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8704 for (j = 0;j < batchnumvertices;j++)
8706 // identical to Q3A's method, but executed in worldspace so
8707 // carried models can be shiny too
8709 float viewer[3], d, reflected[3], worldreflected[3];
8711 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8712 // VectorNormalize(viewer);
8714 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8716 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8717 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8718 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8719 // note: this is proportinal to viewer, so we can normalize later
8721 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8722 VectorNormalize(worldreflected);
8724 // note: this sphere map only uses world x and z!
8725 // so positive and negative y will LOOK THE SAME.
8726 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8727 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8731 // the only tcmod that needs software vertex processing is turbulent, so
8732 // check for it here and apply the changes if needed
8733 // and we only support that as the first one
8734 // (handling a mixture of turbulent and other tcmods would be problematic
8735 // without punting it entirely to a software path)
8736 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8738 amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8739 animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8740 // rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8741 // rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8742 // rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8743 for (j = 0;j < batchnumvertices;j++)
8745 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);
8746 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1] ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8751 if (needsupdate & batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP))
8753 // convert the modified arrays to vertex structs
8754 // rsurface.batchvertexmesh = R_FrameData_Alloc(batchnumvertices * sizeof(r_vertexmesh_t));
8755 // rsurface.batchvertexmesh_vertexbuffer = NULL;
8756 // rsurface.batchvertexmesh_bufferoffset = 0;
8757 if (batchneed & BATCHNEED_VERTEXMESH_VERTEX)
8758 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8759 VectorCopy(rsurface.batchvertex3f + 3*j, vertexmesh->vertex3f);
8760 if (batchneed & BATCHNEED_VERTEXMESH_NORMAL)
8761 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8762 VectorCopy(rsurface.batchnormal3f + 3*j, vertexmesh->normal3f);
8763 if (batchneed & BATCHNEED_VERTEXMESH_VECTOR)
8765 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8767 VectorCopy(rsurface.batchsvector3f + 3*j, vertexmesh->svector3f);
8768 VectorCopy(rsurface.batchtvector3f + 3*j, vertexmesh->tvector3f);
8771 if ((batchneed & BATCHNEED_VERTEXMESH_VERTEXCOLOR) && rsurface.batchlightmapcolor4f)
8772 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8773 Vector4Copy(rsurface.batchlightmapcolor4f + 4*j, vertexmesh->color4f);
8774 if (batchneed & BATCHNEED_VERTEXMESH_TEXCOORD)
8775 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8776 Vector2Copy(rsurface.batchtexcoordtexture2f + 2*j, vertexmesh->texcoordtexture2f);
8777 if ((batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP) && rsurface.batchtexcoordlightmap2f)
8778 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8779 Vector2Copy(rsurface.batchtexcoordlightmap2f + 2*j, vertexmesh->texcoordlightmap2f);
8780 if ((batchneed & BATCHNEED_VERTEXMESH_SKELETAL) && rsurface.batchskeletalindex4ub)
8782 for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8784 Vector4Copy(rsurface.batchskeletalindex4ub + 4*j, vertexmesh->skeletalindex4ub);
8785 Vector4Copy(rsurface.batchskeletalweight4ub + 4*j, vertexmesh->skeletalweight4ub);
8790 // upload buffer data for the dynamic batch
8791 if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicvertex.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo)
8793 if (rsurface.batchvertexmesh)
8794 rsurface.batchvertexmesh_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(r_vertexmesh_t), rsurface.batchvertexmesh, R_BUFFERDATA_VERTEX, &rsurface.batchvertexmesh_bufferoffset);
8797 if (rsurface.batchvertex3f)
8798 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
8799 if (rsurface.batchsvector3f)
8800 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
8801 if (rsurface.batchtvector3f)
8802 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
8803 if (rsurface.batchnormal3f)
8804 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
8805 if (rsurface.batchlightmapcolor4f)
8806 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
8807 if (rsurface.batchtexcoordtexture2f)
8808 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
8809 if (rsurface.batchtexcoordlightmap2f)
8810 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
8811 if (rsurface.batchskeletalindex4ub)
8812 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
8813 if (rsurface.batchskeletalweight4ub)
8814 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
8816 if (rsurface.batchelement3s)
8817 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
8818 else if (rsurface.batchelement3i)
8819 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
8823 void RSurf_DrawBatch(void)
8825 // sometimes a zero triangle surface (usually a degenerate patch) makes it
8826 // through the pipeline, killing it earlier in the pipeline would have
8827 // per-surface overhead rather than per-batch overhead, so it's best to
8828 // reject it here, before it hits glDraw.
8829 if (rsurface.batchnumtriangles == 0)
8832 // batch debugging code
8833 if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8839 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8840 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8843 for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8845 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8847 if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8848 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);
8855 if (rsurface.batchmultidraw)
8857 // issue multiple draws rather than copying index data
8858 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8859 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8860 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8861 for (i = 0;i < numsurfaces;)
8863 // combine consecutive surfaces as one draw
8864 for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8865 if (surfacelist[j] != surfacelist[k] + 1)
8867 firstvertex = surfacelist[i]->num_firstvertex;
8868 endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8869 firsttriangle = surfacelist[i]->num_firsttriangle;
8870 endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8871 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);
8877 // there is only one consecutive run of index data (may have been combined)
8878 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);
8882 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8884 // pick the closest matching water plane
8885 int planeindex, vertexindex, bestplaneindex = -1;
8889 r_waterstate_waterplane_t *p;
8890 qboolean prepared = false;
8892 for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8894 if(p->camera_entity != rsurface.texture->camera_entity)
8899 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8901 if(rsurface.batchnumvertices == 0)
8904 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8906 Matrix4x4_Transform(&rsurface.matrix, v, vert);
8907 d += fabs(PlaneDiff(vert, &p->plane));
8909 if (bestd > d || bestplaneindex < 0)
8912 bestplaneindex = planeindex;
8915 return bestplaneindex;
8916 // NOTE: this MAY return a totally unrelated water plane; we can ignore
8917 // this situation though, as it might be better to render single larger
8918 // batches with useless stuff (backface culled for example) than to
8919 // render multiple smaller batches
8922 void RSurf_SetupDepthAndCulling(void)
8924 // submodels are biased to avoid z-fighting with world surfaces that they
8925 // may be exactly overlapping (avoids z-fighting artifacts on certain
8926 // doors and things in Quake maps)
8927 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8928 GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8929 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8930 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8933 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8936 // transparent sky would be ridiculous
8937 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8939 R_SetupShader_Generic_NoTexture(false, false);
8940 skyrenderlater = true;
8941 RSurf_SetupDepthAndCulling();
8944 // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8945 if (r_sky_scissor.integer)
8947 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8948 for (i = 0; i < texturenumsurfaces; i++)
8950 const msurface_t *surf = texturesurfacelist[i];
8953 float mins[3], maxs[3];
8955 for (j = 0, v = rsurface.batchvertex3f + 3 * surf->num_firstvertex; j < surf->num_vertices; j++, v += 3)
8957 Matrix4x4_Transform(&rsurface.matrix, v, p);
8960 if (mins[0] > p[0]) mins[0] = p[0];
8961 if (mins[1] > p[1]) mins[1] = p[1];
8962 if (mins[2] > p[2]) mins[2] = p[2];
8963 if (maxs[0] < p[0]) maxs[0] = p[0];
8964 if (maxs[1] < p[1]) maxs[1] = p[1];
8965 if (maxs[2] < p[2]) maxs[2] = p[2];
8969 VectorCopy(p, mins);
8970 VectorCopy(p, maxs);
8973 if (!R_ScissorForBBox(mins, maxs, scissor))
8977 if (skyscissor[0] > scissor[0])
8979 skyscissor[2] += skyscissor[0] - scissor[0];
8980 skyscissor[0] = scissor[0];
8982 if (skyscissor[1] > scissor[1])
8984 skyscissor[3] += skyscissor[1] - scissor[1];
8985 skyscissor[1] = scissor[1];
8987 if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8988 skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8989 if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8990 skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8993 Vector4Copy(scissor, skyscissor);
8998 // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8999 // skymasking on them, and Quake3 never did sky masking (unlike
9000 // software Quake and software Quake2), so disable the sky masking
9001 // in Quake3 maps as it causes problems with q3map2 sky tricks,
9002 // and skymasking also looks very bad when noclipping outside the
9003 // level, so don't use it then either.
9004 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)
9006 R_Mesh_ResetTextureState();
9007 if (skyrendermasked)
9009 R_SetupShader_DepthOrShadow(false, false, false);
9010 // depth-only (masking)
9011 GL_ColorMask(0, 0, 0, 0);
9012 // just to make sure that braindead drivers don't draw
9013 // anything despite that colormask...
9014 GL_BlendFunc(GL_ZERO, GL_ONE);
9015 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9016 R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9020 R_SetupShader_Generic_NoTexture(false, false);
9022 GL_BlendFunc(GL_ONE, GL_ZERO);
9023 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9024 GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
9025 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9028 if (skyrendermasked)
9029 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
9031 R_Mesh_ResetTextureState();
9032 GL_Color(1, 1, 1, 1);
9035 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
9036 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
9037 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
9039 if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
9043 // render screenspace normalmap to texture
9045 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false);
9050 // bind lightmap texture
9052 // water/refraction/reflection/camera surfaces have to be handled specially
9053 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
9055 int start, end, startplaneindex;
9056 for (start = 0;start < texturenumsurfaces;start = end)
9058 startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
9059 if(startplaneindex < 0)
9061 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
9062 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
9066 for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
9068 // now that we have a batch using the same planeindex, render it
9069 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
9071 // render water or distortion background
9073 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
9075 // blend surface on top
9076 GL_DepthMask(false);
9077 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false);
9080 else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
9082 // render surface with reflection texture as input
9083 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
9084 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
9091 // render surface batch normally
9092 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
9093 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0);
9097 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
9101 r_vertexgeneric_t *batchvertex;
9103 texture_t *t = rsurface.texture;
9105 // R_Mesh_ResetTextureState();
9106 R_SetupShader_Generic_NoTexture(false, false);
9108 if(t && t->currentskinframe)
9110 memcpy(c, t->currentskinframe->avgcolor, sizeof(c));
9111 c[3] *= t->currentalpha;
9121 if (t->pantstexture || t->shirttexture)
9123 c[0] = 0.5 * (t->render_colormap_pants[0] * 0.3 + t->render_colormap_shirt[0] * 0.7);
9124 c[1] = 0.5 * (t->render_colormap_pants[1] * 0.3 + t->render_colormap_shirt[1] * 0.7);
9125 c[2] = 0.5 * (t->render_colormap_pants[2] * 0.3 + t->render_colormap_shirt[2] * 0.7);
9128 // brighten it up (as texture value 127 means "unlit")
9129 c[0] *= 2 * r_refdef.view.colorscale;
9130 c[1] *= 2 * r_refdef.view.colorscale;
9131 c[2] *= 2 * r_refdef.view.colorscale;
9133 if(t->currentmaterialflags & MATERIALFLAG_WATERALPHA)
9134 c[3] *= r_wateralpha.value;
9136 if(t->currentmaterialflags & MATERIALFLAG_ALPHA && c[3] != 1)
9138 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9139 GL_DepthMask(false);
9141 else if(t->currentmaterialflags & MATERIALFLAG_ADD)
9143 GL_BlendFunc(GL_ONE, GL_ONE);
9144 GL_DepthMask(false);
9146 else if(t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
9148 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // can't do alpha test without texture, so let's blend instead
9149 GL_DepthMask(false);
9151 else if(t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
9153 GL_BlendFunc(t->customblendfunc[0], t->customblendfunc[1]);
9154 GL_DepthMask(false);
9158 GL_BlendFunc(GL_ONE, GL_ZERO);
9159 GL_DepthMask(writedepth);
9162 if (!r_refdef.view.showdebug)
9164 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9165 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices);
9166 for (j = 0, vi = 0;j < rsurface.batchnumvertices;j++, vi++)
9168 VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
9169 Vector4Set(batchvertex[vi].color4f, 0, 0, 0, 1);
9171 R_Mesh_PrepareVertices_Generic_Unlock();
9174 else if (r_showsurfaces.integer == 4)
9176 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9177 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices);
9178 for (j = 0, vi = 0;j < rsurface.batchnumvertices;j++, vi++)
9180 float d = (vi << 3) * (1.0f / 256.0f);
9181 VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
9182 Vector4Set(batchvertex[vi].color4f, d, d, d, 1);
9184 R_Mesh_PrepareVertices_Generic_Unlock();
9187 else if (r_showsurfaces.integer == 2)
9190 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9191 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(3*rsurface.batchnumtriangles);
9192 for (j = 0, e = rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle;j < rsurface.batchnumtriangles;j++, e += 3)
9194 float d = ((j + rsurface.batchfirsttriangle) << 3) * (1.0f / 256.0f);
9195 VectorCopy(rsurface.batchvertex3f + 3*e[0], batchvertex[j*3+0].vertex3f);
9196 VectorCopy(rsurface.batchvertex3f + 3*e[1], batchvertex[j*3+1].vertex3f);
9197 VectorCopy(rsurface.batchvertex3f + 3*e[2], batchvertex[j*3+2].vertex3f);
9198 Vector4Set(batchvertex[j*3+0].color4f, d, d, d, 1);
9199 Vector4Set(batchvertex[j*3+1].color4f, d, d, d, 1);
9200 Vector4Set(batchvertex[j*3+2].color4f, d, d, d, 1);
9202 R_Mesh_PrepareVertices_Generic_Unlock();
9203 R_Mesh_Draw(0, rsurface.batchnumtriangles*3, 0, rsurface.batchnumtriangles, NULL, NULL, 0, NULL, NULL, 0);
9207 int texturesurfaceindex;
9209 const msurface_t *surface;
9210 float surfacecolor4f[4];
9211 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9212 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchfirstvertex + rsurface.batchnumvertices);
9214 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
9216 surface = texturesurfacelist[texturesurfaceindex];
9217 k = (int)(((size_t)surface) / sizeof(msurface_t));
9218 Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
9219 for (j = 0;j < surface->num_vertices;j++)
9221 VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
9222 Vector4Copy(surfacecolor4f, batchvertex[vi].color4f);
9226 R_Mesh_PrepareVertices_Generic_Unlock();
9231 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
9234 RSurf_SetupDepthAndCulling();
9235 if (r_showsurfaces.integer)
9237 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
9240 switch (vid.renderpath)
9242 case RENDERPATH_GL20:
9243 case RENDERPATH_GLES2:
9244 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
9250 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9253 int texturenumsurfaces, endsurface;
9255 const msurface_t *surface;
9256 const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
9258 RSurf_ActiveModelEntity(ent, true, true, false);
9260 if (r_transparentdepthmasking.integer)
9262 qboolean setup = false;
9263 for (i = 0;i < numsurfaces;i = j)
9266 surface = rsurface.modelsurfaces + surfacelist[i];
9267 texture = surface->texture;
9268 rsurface.texture = R_GetCurrentTexture(texture);
9269 rsurface.lightmaptexture = NULL;
9270 rsurface.deluxemaptexture = NULL;
9271 rsurface.uselightmaptexture = false;
9272 // scan ahead until we find a different texture
9273 endsurface = min(i + 1024, numsurfaces);
9274 texturenumsurfaces = 0;
9275 texturesurfacelist[texturenumsurfaces++] = surface;
9276 for (;j < endsurface;j++)
9278 surface = rsurface.modelsurfaces + surfacelist[j];
9279 if (texture != surface->texture)
9281 texturesurfacelist[texturenumsurfaces++] = surface;
9283 if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
9285 // render the range of surfaces as depth
9289 GL_ColorMask(0,0,0,0);
9292 GL_BlendFunc(GL_ONE, GL_ZERO);
9294 // R_Mesh_ResetTextureState();
9296 RSurf_SetupDepthAndCulling();
9297 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9298 R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9299 R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9303 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
9306 for (i = 0;i < numsurfaces;i = j)
9309 surface = rsurface.modelsurfaces + surfacelist[i];
9310 texture = surface->texture;
9311 rsurface.texture = R_GetCurrentTexture(texture);
9312 // scan ahead until we find a different texture
9313 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
9314 texturenumsurfaces = 0;
9315 texturesurfacelist[texturenumsurfaces++] = surface;
9316 if(FAKELIGHT_ENABLED)
9318 rsurface.lightmaptexture = NULL;
9319 rsurface.deluxemaptexture = NULL;
9320 rsurface.uselightmaptexture = false;
9321 for (;j < endsurface;j++)
9323 surface = rsurface.modelsurfaces + surfacelist[j];
9324 if (texture != surface->texture)
9326 texturesurfacelist[texturenumsurfaces++] = surface;
9331 rsurface.lightmaptexture = surface->lightmaptexture;
9332 rsurface.deluxemaptexture = surface->deluxemaptexture;
9333 rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
9334 for (;j < endsurface;j++)
9336 surface = rsurface.modelsurfaces + surfacelist[j];
9337 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
9339 texturesurfacelist[texturenumsurfaces++] = surface;
9342 // render the range of surfaces
9343 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false);
9345 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
9348 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9350 // transparent surfaces get pushed off into the transparent queue
9351 int surfacelistindex;
9352 const msurface_t *surface;
9353 vec3_t tempcenter, center;
9354 for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
9356 surface = texturesurfacelist[surfacelistindex];
9357 if (r_transparent_sortsurfacesbynearest.integer)
9359 tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
9360 tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
9361 tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
9365 tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
9366 tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
9367 tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
9369 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
9370 if (rsurface.entity->transparent_offset) // transparent offset
9372 center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
9373 center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
9374 center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
9376 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);
9380 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9382 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
9384 if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
9386 RSurf_SetupDepthAndCulling();
9387 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9388 R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9389 R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9393 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass)
9397 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
9400 if (!rsurface.texture->currentnumlayers)
9402 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
9403 R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9405 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
9407 else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
9408 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
9409 else if (!rsurface.texture->currentnumlayers)
9411 else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
9413 // in the deferred case, transparent surfaces were queued during prepass
9414 if (!r_shadow_usingdeferredprepass)
9415 R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9419 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
9420 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass);
9425 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass)
9429 R_FrameData_SetMark();
9430 // break the surface list down into batches by texture and use of lightmapping
9431 for (i = 0;i < numsurfaces;i = j)
9434 // texture is the base texture pointer, rsurface.texture is the
9435 // current frame/skin the texture is directing us to use (for example
9436 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
9437 // use skin 1 instead)
9438 texture = surfacelist[i]->texture;
9439 rsurface.texture = R_GetCurrentTexture(texture);
9440 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
9442 // if this texture is not the kind we want, skip ahead to the next one
9443 for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9447 if(FAKELIGHT_ENABLED || depthonly || prepass)
9449 rsurface.lightmaptexture = NULL;
9450 rsurface.deluxemaptexture = NULL;
9451 rsurface.uselightmaptexture = false;
9452 // simply scan ahead until we find a different texture or lightmap state
9453 for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9458 rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
9459 rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
9460 rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
9461 // simply scan ahead until we find a different texture or lightmap state
9462 for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
9465 // render the range of surfaces
9466 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass);
9468 R_FrameData_ReturnToMark();
9471 float locboxvertex3f[6*4*3] =
9473 1,0,1, 1,0,0, 1,1,0, 1,1,1,
9474 0,1,1, 0,1,0, 0,0,0, 0,0,1,
9475 1,1,1, 1,1,0, 0,1,0, 0,1,1,
9476 0,0,1, 0,0,0, 1,0,0, 1,0,1,
9477 0,0,1, 1,0,1, 1,1,1, 0,1,1,
9478 1,0,0, 0,0,0, 0,1,0, 1,1,0
9481 unsigned short locboxelements[6*2*3] =
9491 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9494 cl_locnode_t *loc = (cl_locnode_t *)ent;
9496 float vertex3f[6*4*3];
9498 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9499 GL_DepthMask(false);
9500 GL_DepthRange(0, 1);
9501 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9503 GL_CullFace(GL_NONE);
9504 R_EntityMatrix(&identitymatrix);
9506 // R_Mesh_ResetTextureState();
9509 GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9510 ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9511 ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9512 surfacelist[0] < 0 ? 0.5f : 0.125f);
9514 if (VectorCompare(loc->mins, loc->maxs))
9516 VectorSet(size, 2, 2, 2);
9517 VectorMA(loc->mins, -0.5f, size, mins);
9521 VectorCopy(loc->mins, mins);
9522 VectorSubtract(loc->maxs, loc->mins, size);
9525 for (i = 0;i < 6*4*3;)
9526 for (j = 0;j < 3;j++, i++)
9527 vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9529 R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9530 R_SetupShader_Generic_NoTexture(false, false);
9531 R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9534 void R_DrawLocs(void)
9537 cl_locnode_t *loc, *nearestloc;
9539 nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9540 for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9542 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9543 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9547 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9549 if (decalsystem->decals)
9550 Mem_Free(decalsystem->decals);
9551 memset(decalsystem, 0, sizeof(*decalsystem));
9554 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)
9560 // expand or initialize the system
9561 if (decalsystem->maxdecals <= decalsystem->numdecals)
9563 decalsystem_t old = *decalsystem;
9564 qboolean useshortelements;
9565 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9566 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9567 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)));
9568 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9569 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9570 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9571 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9572 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9573 if (decalsystem->numdecals)
9574 memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9576 Mem_Free(old.decals);
9577 for (i = 0;i < decalsystem->maxdecals*3;i++)
9578 decalsystem->element3i[i] = i;
9579 if (useshortelements)
9580 for (i = 0;i < decalsystem->maxdecals*3;i++)
9581 decalsystem->element3s[i] = i;
9584 // grab a decal and search for another free slot for the next one
9585 decals = decalsystem->decals;
9586 decal = decalsystem->decals + (i = decalsystem->freedecal++);
9587 for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9589 decalsystem->freedecal = i;
9590 if (decalsystem->numdecals <= i)
9591 decalsystem->numdecals = i + 1;
9593 // initialize the decal
9595 decal->triangleindex = triangleindex;
9596 decal->surfaceindex = surfaceindex;
9597 decal->decalsequence = decalsequence;
9598 decal->color4f[0][0] = c0[0];
9599 decal->color4f[0][1] = c0[1];
9600 decal->color4f[0][2] = c0[2];
9601 decal->color4f[0][3] = 1;
9602 decal->color4f[1][0] = c1[0];
9603 decal->color4f[1][1] = c1[1];
9604 decal->color4f[1][2] = c1[2];
9605 decal->color4f[1][3] = 1;
9606 decal->color4f[2][0] = c2[0];
9607 decal->color4f[2][1] = c2[1];
9608 decal->color4f[2][2] = c2[2];
9609 decal->color4f[2][3] = 1;
9610 decal->vertex3f[0][0] = v0[0];
9611 decal->vertex3f[0][1] = v0[1];
9612 decal->vertex3f[0][2] = v0[2];
9613 decal->vertex3f[1][0] = v1[0];
9614 decal->vertex3f[1][1] = v1[1];
9615 decal->vertex3f[1][2] = v1[2];
9616 decal->vertex3f[2][0] = v2[0];
9617 decal->vertex3f[2][1] = v2[1];
9618 decal->vertex3f[2][2] = v2[2];
9619 decal->texcoord2f[0][0] = t0[0];
9620 decal->texcoord2f[0][1] = t0[1];
9621 decal->texcoord2f[1][0] = t1[0];
9622 decal->texcoord2f[1][1] = t1[1];
9623 decal->texcoord2f[2][0] = t2[0];
9624 decal->texcoord2f[2][1] = t2[1];
9625 TriangleNormal(v0, v1, v2, decal->plane);
9626 VectorNormalize(decal->plane);
9627 decal->plane[3] = DotProduct(v0, decal->plane);
9630 extern cvar_t cl_decals_bias;
9631 extern cvar_t cl_decals_models;
9632 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9633 // baseparms, parms, temps
9634 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)
9639 const float *vertex3f;
9640 const float *normal3f;
9642 float points[2][9][3];
9649 e = rsurface.modelelement3i + 3*triangleindex;
9651 vertex3f = rsurface.modelvertex3f;
9652 normal3f = rsurface.modelnormal3f;
9656 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9658 index = 3*e[cornerindex];
9659 VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9664 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9666 index = 3*e[cornerindex];
9667 VectorCopy(vertex3f + index, v[cornerindex]);
9672 //TriangleNormal(v[0], v[1], v[2], normal);
9673 //if (DotProduct(normal, localnormal) < 0.0f)
9675 // clip by each of the box planes formed from the projection matrix
9676 // if anything survives, we emit the decal
9677 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]);
9680 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]);
9683 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]);
9686 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]);
9689 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]);
9692 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]);
9695 // some part of the triangle survived, so we have to accept it...
9698 // dynamic always uses the original triangle
9700 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9702 index = 3*e[cornerindex];
9703 VectorCopy(vertex3f + index, v[cornerindex]);
9706 for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9708 // convert vertex positions to texcoords
9709 Matrix4x4_Transform(projection, v[cornerindex], temp);
9710 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9711 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9712 // calculate distance fade from the projection origin
9713 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9714 f = bound(0.0f, f, 1.0f);
9715 c[cornerindex][0] = r * f;
9716 c[cornerindex][1] = g * f;
9717 c[cornerindex][2] = b * f;
9718 c[cornerindex][3] = 1.0f;
9719 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9722 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);
9724 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9725 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);
9727 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)
9729 matrix4x4_t projection;
9730 decalsystem_t *decalsystem;
9733 const msurface_t *surface;
9734 const msurface_t *surfaces;
9735 const int *surfacelist;
9736 const texture_t *texture;
9739 int surfacelistindex;
9742 float localorigin[3];
9743 float localnormal[3];
9751 int bih_triangles_count;
9752 int bih_triangles[256];
9753 int bih_surfaces[256];
9755 decalsystem = &ent->decalsystem;
9757 if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9759 R_DecalSystem_Reset(&ent->decalsystem);
9763 if (!model->brush.data_leafs && !cl_decals_models.integer)
9765 if (decalsystem->model)
9766 R_DecalSystem_Reset(decalsystem);
9770 if (decalsystem->model != model)
9771 R_DecalSystem_Reset(decalsystem);
9772 decalsystem->model = model;
9774 RSurf_ActiveModelEntity(ent, true, false, false);
9776 Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9777 Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9778 VectorNormalize(localnormal);
9779 localsize = worldsize*rsurface.inversematrixscale;
9780 localmins[0] = localorigin[0] - localsize;
9781 localmins[1] = localorigin[1] - localsize;
9782 localmins[2] = localorigin[2] - localsize;
9783 localmaxs[0] = localorigin[0] + localsize;
9784 localmaxs[1] = localorigin[1] + localsize;
9785 localmaxs[2] = localorigin[2] + localsize;
9787 //VectorCopy(localnormal, planes[4]);
9788 //VectorVectors(planes[4], planes[2], planes[0]);
9789 AnglesFromVectors(angles, localnormal, NULL, false);
9790 AngleVectors(angles, planes[0], planes[2], planes[4]);
9791 VectorNegate(planes[0], planes[1]);
9792 VectorNegate(planes[2], planes[3]);
9793 VectorNegate(planes[4], planes[5]);
9794 planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9795 planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9796 planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9797 planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9798 planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9799 planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9804 matrix4x4_t forwardprojection;
9805 Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9806 Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9811 float projectionvector[4][3];
9812 VectorScale(planes[0], ilocalsize, projectionvector[0]);
9813 VectorScale(planes[2], ilocalsize, projectionvector[1]);
9814 VectorScale(planes[4], ilocalsize, projectionvector[2]);
9815 projectionvector[0][0] = planes[0][0] * ilocalsize;
9816 projectionvector[0][1] = planes[1][0] * ilocalsize;
9817 projectionvector[0][2] = planes[2][0] * ilocalsize;
9818 projectionvector[1][0] = planes[0][1] * ilocalsize;
9819 projectionvector[1][1] = planes[1][1] * ilocalsize;
9820 projectionvector[1][2] = planes[2][1] * ilocalsize;
9821 projectionvector[2][0] = planes[0][2] * ilocalsize;
9822 projectionvector[2][1] = planes[1][2] * ilocalsize;
9823 projectionvector[2][2] = planes[2][2] * ilocalsize;
9824 projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9825 projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9826 projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9827 Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9831 dynamic = model->surfmesh.isanimated;
9832 numsurfacelist = model->nummodelsurfaces;
9833 surfacelist = model->sortedmodelsurfaces;
9834 surfaces = model->data_surfaces;
9837 bih_triangles_count = -1;
9840 if(model->render_bih.numleafs)
9841 bih = &model->render_bih;
9842 else if(model->collision_bih.numleafs)
9843 bih = &model->collision_bih;
9846 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9847 if(bih_triangles_count == 0)
9849 if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9851 if(bih_triangles_count > 0)
9853 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9855 surfaceindex = bih_surfaces[triangleindex];
9856 surface = surfaces + surfaceindex;
9857 texture = surface->texture;
9858 if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9860 if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9862 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9867 for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
9869 surfaceindex = surfacelist[surfacelistindex];
9870 surface = surfaces + surfaceindex;
9871 // check cull box first because it rejects more than any other check
9872 if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9874 // skip transparent surfaces
9875 texture = surface->texture;
9876 if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9878 if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9880 numtriangles = surface->num_triangles;
9881 for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9882 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9887 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9888 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)
9890 int renderentityindex;
9893 entity_render_t *ent;
9895 if (!cl_decals_newsystem.integer)
9898 worldmins[0] = worldorigin[0] - worldsize;
9899 worldmins[1] = worldorigin[1] - worldsize;
9900 worldmins[2] = worldorigin[2] - worldsize;
9901 worldmaxs[0] = worldorigin[0] + worldsize;
9902 worldmaxs[1] = worldorigin[1] + worldsize;
9903 worldmaxs[2] = worldorigin[2] + worldsize;
9905 R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9907 for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9909 ent = r_refdef.scene.entities[renderentityindex];
9910 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9913 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9917 typedef struct r_decalsystem_splatqueue_s
9924 unsigned int decalsequence;
9926 r_decalsystem_splatqueue_t;
9928 int r_decalsystem_numqueued = 0;
9929 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9931 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)
9933 r_decalsystem_splatqueue_t *queue;
9935 if (!cl_decals_newsystem.integer || r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9938 queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9939 VectorCopy(worldorigin, queue->worldorigin);
9940 VectorCopy(worldnormal, queue->worldnormal);
9941 Vector4Set(queue->color, r, g, b, a);
9942 Vector4Set(queue->tcrange, s1, t1, s2, t2);
9943 queue->worldsize = worldsize;
9944 queue->decalsequence = cl.decalsequence++;
9947 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9950 r_decalsystem_splatqueue_t *queue;
9952 for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9953 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);
9954 r_decalsystem_numqueued = 0;
9957 extern cvar_t cl_decals_max;
9958 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9961 decalsystem_t *decalsystem = &ent->decalsystem;
9963 unsigned int killsequence;
9968 if (!decalsystem->numdecals)
9971 if (r_showsurfaces.integer)
9974 if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9976 R_DecalSystem_Reset(decalsystem);
9980 killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9981 lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9983 if (decalsystem->lastupdatetime)
9984 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9987 decalsystem->lastupdatetime = r_refdef.scene.time;
9988 numdecals = decalsystem->numdecals;
9990 for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9992 if (decal->color4f[0][3])
9994 decal->lived += frametime;
9995 if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9997 memset(decal, 0, sizeof(*decal));
9998 if (decalsystem->freedecal > i)
9999 decalsystem->freedecal = i;
10003 decal = decalsystem->decals;
10004 while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
10007 // collapse the array by shuffling the tail decals into the gaps
10010 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
10011 decalsystem->freedecal++;
10012 if (decalsystem->freedecal == numdecals)
10014 decal[decalsystem->freedecal] = decal[--numdecals];
10017 decalsystem->numdecals = numdecals;
10019 if (numdecals <= 0)
10021 // if there are no decals left, reset decalsystem
10022 R_DecalSystem_Reset(decalsystem);
10026 extern skinframe_t *decalskinframe;
10027 static void R_DrawModelDecals_Entity(entity_render_t *ent)
10030 decalsystem_t *decalsystem = &ent->decalsystem;
10039 const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
10042 numdecals = decalsystem->numdecals;
10046 if (r_showsurfaces.integer)
10049 if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
10051 R_DecalSystem_Reset(decalsystem);
10055 // if the model is static it doesn't matter what value we give for
10056 // wantnormals and wanttangents, so this logic uses only rules applicable
10057 // to a model, knowing that they are meaningless otherwise
10058 RSurf_ActiveModelEntity(ent, false, false, false);
10060 decalsystem->lastupdatetime = r_refdef.scene.time;
10062 faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
10064 // update vertex positions for animated models
10065 v3f = decalsystem->vertex3f;
10066 c4f = decalsystem->color4f;
10067 t2f = decalsystem->texcoord2f;
10068 for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
10070 if (!decal->color4f[0][3])
10073 if (surfacevisible && !surfacevisible[decal->surfaceindex])
10077 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
10080 // update color values for fading decals
10081 if (decal->lived >= cl_decals_time.value)
10082 alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
10086 c4f[ 0] = decal->color4f[0][0] * alpha;
10087 c4f[ 1] = decal->color4f[0][1] * alpha;
10088 c4f[ 2] = decal->color4f[0][2] * alpha;
10090 c4f[ 4] = decal->color4f[1][0] * alpha;
10091 c4f[ 5] = decal->color4f[1][1] * alpha;
10092 c4f[ 6] = decal->color4f[1][2] * alpha;
10094 c4f[ 8] = decal->color4f[2][0] * alpha;
10095 c4f[ 9] = decal->color4f[2][1] * alpha;
10096 c4f[10] = decal->color4f[2][2] * alpha;
10099 t2f[0] = decal->texcoord2f[0][0];
10100 t2f[1] = decal->texcoord2f[0][1];
10101 t2f[2] = decal->texcoord2f[1][0];
10102 t2f[3] = decal->texcoord2f[1][1];
10103 t2f[4] = decal->texcoord2f[2][0];
10104 t2f[5] = decal->texcoord2f[2][1];
10106 // update vertex positions for animated models
10107 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
10109 e = rsurface.modelelement3i + 3*decal->triangleindex;
10110 VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
10111 VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
10112 VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
10116 VectorCopy(decal->vertex3f[0], v3f);
10117 VectorCopy(decal->vertex3f[1], v3f + 3);
10118 VectorCopy(decal->vertex3f[2], v3f + 6);
10121 if (r_refdef.fogenabled)
10123 alpha = RSurf_FogVertex(v3f);
10124 VectorScale(c4f, alpha, c4f);
10125 alpha = RSurf_FogVertex(v3f + 3);
10126 VectorScale(c4f + 4, alpha, c4f + 4);
10127 alpha = RSurf_FogVertex(v3f + 6);
10128 VectorScale(c4f + 8, alpha, c4f + 8);
10139 r_refdef.stats[r_stat_drawndecals] += numtris;
10141 // now render the decals all at once
10142 // (this assumes they all use one particle font texture!)
10143 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);
10144 // R_Mesh_ResetTextureState();
10145 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
10146 GL_DepthMask(false);
10147 GL_DepthRange(0, 1);
10148 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
10149 GL_DepthTest(true);
10150 GL_CullFace(GL_NONE);
10151 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
10152 R_SetupShader_Generic(decalskinframe->base, NULL, GL_MODULATE, 1, false, false, false);
10153 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
10157 static void R_DrawModelDecals(void)
10161 // fade faster when there are too many decals
10162 numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
10163 for (i = 0;i < r_refdef.scene.numentities;i++)
10164 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
10166 R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
10167 for (i = 0;i < r_refdef.scene.numentities;i++)
10168 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
10169 R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
10171 R_DecalSystem_ApplySplatEntitiesQueue();
10173 numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
10174 for (i = 0;i < r_refdef.scene.numentities;i++)
10175 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
10177 r_refdef.stats[r_stat_totaldecals] += numdecals;
10179 if (r_showsurfaces.integer)
10182 R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
10184 for (i = 0;i < r_refdef.scene.numentities;i++)
10186 if (!r_refdef.viewcache.entityvisible[i])
10188 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
10189 R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
10193 extern cvar_t mod_collision_bih;
10194 static void R_DrawDebugModel(void)
10196 entity_render_t *ent = rsurface.entity;
10197 int i, j, flagsmask;
10198 const msurface_t *surface;
10199 dp_model_t *model = ent->model;
10201 if (!sv.active && !cls.demoplayback && ent != r_refdef.scene.worldentity)
10204 if (r_showoverdraw.value > 0)
10206 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
10207 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
10208 R_SetupShader_Generic_NoTexture(false, false);
10209 GL_DepthTest(false);
10210 GL_DepthMask(false);
10211 GL_DepthRange(0, 1);
10212 GL_BlendFunc(GL_ONE, GL_ONE);
10213 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10215 if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10217 rsurface.texture = R_GetCurrentTexture(surface->texture);
10218 if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10220 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
10221 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
10222 if (!rsurface.texture->currentlayers->depthmask)
10223 GL_Color(c, 0, 0, 1.0f);
10224 else if (ent == r_refdef.scene.worldentity)
10225 GL_Color(c, c, c, 1.0f);
10227 GL_Color(0, c, 0, 1.0f);
10228 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
10232 rsurface.texture = NULL;
10235 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
10237 // R_Mesh_ResetTextureState();
10238 R_SetupShader_Generic_NoTexture(false, false);
10239 GL_DepthRange(0, 1);
10240 GL_DepthTest(!r_showdisabledepthtest.integer);
10241 GL_DepthMask(false);
10242 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10244 if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
10248 qboolean cullbox = false;
10249 const q3mbrush_t *brush;
10250 const bih_t *bih = &model->collision_bih;
10251 const bih_leaf_t *bihleaf;
10252 float vertex3f[3][3];
10253 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
10254 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
10256 if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
10258 switch (bihleaf->type)
10261 brush = model->brush.data_brushes + bihleaf->itemindex;
10262 if (brush->colbrushf && brush->colbrushf->numtriangles)
10264 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);
10265 R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
10266 R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
10269 case BIH_COLLISIONTRIANGLE:
10270 triangleindex = bihleaf->itemindex;
10271 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
10272 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
10273 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
10274 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);
10275 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
10276 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
10278 case BIH_RENDERTRIANGLE:
10279 triangleindex = bihleaf->itemindex;
10280 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
10281 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
10282 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
10283 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);
10284 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
10285 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
10291 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
10294 if (r_showtris.value > 0 && qglPolygonMode)
10296 if (r_showdisabledepthtest.integer)
10298 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10299 GL_DepthMask(false);
10303 GL_BlendFunc(GL_ONE, GL_ZERO);
10304 GL_DepthMask(true);
10306 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
10307 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10309 if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10311 rsurface.texture = R_GetCurrentTexture(surface->texture);
10312 if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10314 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
10315 if (!rsurface.texture->currentlayers->depthmask)
10316 GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
10317 else if (ent == r_refdef.scene.worldentity)
10318 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
10320 GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
10321 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
10325 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
10326 rsurface.texture = NULL;
10330 // FIXME! implement r_shownormals with just triangles
10331 if (r_shownormals.value != 0 && qglBegin)
10335 if (r_showdisabledepthtest.integer)
10337 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10338 GL_DepthMask(false);
10342 GL_BlendFunc(GL_ONE, GL_ZERO);
10343 GL_DepthMask(true);
10345 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10347 if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10349 rsurface.texture = R_GetCurrentTexture(surface->texture);
10350 if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10352 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
10353 qglBegin(GL_LINES);
10354 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
10356 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10358 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10359 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10360 qglVertex3f(v[0], v[1], v[2]);
10361 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10362 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10363 qglVertex3f(v[0], v[1], v[2]);
10366 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
10368 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10370 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10371 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
10372 qglVertex3f(v[0], v[1], v[2]);
10373 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
10374 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10375 qglVertex3f(v[0], v[1], v[2]);
10378 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
10380 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10382 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10383 GL_Color(0, r_refdef.view.colorscale, 0, 1);
10384 qglVertex3f(v[0], v[1], v[2]);
10385 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
10386 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10387 qglVertex3f(v[0], v[1], v[2]);
10390 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
10392 for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10394 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10395 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10396 qglVertex3f(v[0], v[1], v[2]);
10397 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10398 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10399 qglVertex3f(v[0], v[1], v[2]);
10406 rsurface.texture = NULL;
10412 int r_maxsurfacelist = 0;
10413 const msurface_t **r_surfacelist = NULL;
10414 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass)
10416 int i, j, endj, flagsmask;
10417 dp_model_t *model = ent->model;
10418 msurface_t *surfaces;
10419 unsigned char *update;
10420 int numsurfacelist = 0;
10424 if (r_maxsurfacelist < model->num_surfaces)
10426 r_maxsurfacelist = model->num_surfaces;
10428 Mem_Free((msurface_t **)r_surfacelist);
10429 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
10432 if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
10433 RSurf_ActiveModelEntity(ent, false, false, false);
10435 RSurf_ActiveModelEntity(ent, true, true, true);
10436 else if (depthonly)
10437 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
10439 RSurf_ActiveModelEntity(ent, true, true, false);
10441 surfaces = model->data_surfaces;
10442 update = model->brushq1.lightmapupdateflags;
10444 // update light styles
10445 if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0)
10447 model_brush_lightstyleinfo_t *style;
10448 for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
10450 if (style->value != r_refdef.scene.lightstylevalue[style->style])
10452 int *list = style->surfacelist;
10453 style->value = r_refdef.scene.lightstylevalue[style->style];
10454 for (j = 0;j < style->numsurfaces;j++)
10455 update[list[j]] = true;
10460 flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
10464 R_DrawDebugModel();
10465 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10469 rsurface.lightmaptexture = NULL;
10470 rsurface.deluxemaptexture = NULL;
10471 rsurface.uselightmaptexture = false;
10472 rsurface.texture = NULL;
10473 rsurface.rtlight = NULL;
10474 numsurfacelist = 0;
10475 // add visible surfaces to draw list
10476 if (ent == r_refdef.scene.worldentity)
10478 // for the world entity, check surfacevisible
10479 for (i = 0;i < model->nummodelsurfaces;i++)
10481 j = model->sortedmodelsurfaces[i];
10482 if (r_refdef.viewcache.world_surfacevisible[j])
10483 r_surfacelist[numsurfacelist++] = surfaces + j;
10488 // add all surfaces
10489 for (i = 0; i < model->nummodelsurfaces; i++)
10490 r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
10492 // don't do anything if there were no surfaces
10493 if (!numsurfacelist)
10495 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10498 // update lightmaps if needed
10502 for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
10507 R_BuildLightMap(ent, surfaces + j);
10512 R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass);
10514 // add to stats if desired
10515 if (r_speeds.integer && !skysurfaces && !depthonly)
10517 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10518 for (j = 0;j < numsurfacelist;j++)
10519 r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10522 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10525 void R_DebugLine(vec3_t start, vec3_t end)
10527 dp_model_t *mod = CL_Mesh_UI();
10529 int e0, e1, e2, e3;
10530 float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10531 float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10532 float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10535 // transform to screen coords first
10536 Vector4Set(w[0], start[0], start[1], start[2], 1);
10537 Vector4Set(w[1], end[0], end[1], end[2], 1);
10538 R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10539 R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10540 x1 = s[0][0] * vid_conwidth.value / vid.width;
10541 y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10542 x2 = s[1][0] * vid_conwidth.value / vid.width;
10543 y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10544 //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10546 // add the line to the UI mesh for drawing later
10548 // width is measured in real pixels
10549 if (fabs(x2 - x1) > fabs(y2 - y1))
10552 offsety = 0.5f * width * vid_conheight.value / vid.height;
10556 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10559 surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_VERTEXCOLOR), true);
10560 e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10561 e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10562 e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10563 e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10564 Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10565 Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10570 void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass)
10573 static texture_t texture;
10574 static msurface_t surface;
10575 const msurface_t *surfacelist = &surface;
10577 // fake enough texture and surface state to render this geometry
10579 texture.update_lastrenderframe = -1; // regenerate this texture
10580 texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10581 texture.basealpha = 1.0f;
10582 texture.currentskinframe = skinframe;
10583 texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10584 texture.offsetmapping = OFFSETMAPPING_OFF;
10585 texture.offsetscale = 1;
10586 texture.specularscalemod = 1;
10587 texture.specularpowermod = 1;
10588 texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10589 // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
10590 // JUST GREP FOR "specularscalemod = 1".
10592 for (q = 0; q < 3; q++)
10594 texture.render_glowmod[q] = r_refdef.view.colorscale * r_hdr_glowintensity.value;
10595 texture.render_modellight_lightdir[q] = q == 2;
10596 texture.render_modellight_ambient[q] = r_refdef.view.colorscale * r_refdef.scene.ambientintensity;
10597 texture.render_modellight_diffuse[q] = r_refdef.view.colorscale;
10598 texture.render_modellight_specular[q] = r_refdef.view.colorscale;
10599 texture.render_lightmap_ambient[q] = r_refdef.view.colorscale * r_refdef.scene.ambientintensity;
10600 texture.render_lightmap_diffuse[q] = r_refdef.view.colorscale * r_refdef.scene.lightmapintensity;
10601 texture.render_lightmap_specular[q] = r_refdef.view.colorscale;
10602 texture.render_rtlight_diffuse[q] = r_refdef.view.colorscale;
10603 texture.render_rtlight_specular[q] = r_refdef.view.colorscale;
10605 texture.currentalpha = 1.0f;
10607 surface.texture = &texture;
10608 surface.num_triangles = numtriangles;
10609 surface.num_firsttriangle = firsttriangle;
10610 surface.num_vertices = numvertices;
10611 surface.num_firstvertex = firstvertex;
10614 rsurface.texture = R_GetCurrentTexture(surface.texture);
10615 rsurface.lightmaptexture = NULL;
10616 rsurface.deluxemaptexture = NULL;
10617 rsurface.uselightmaptexture = false;
10618 R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);
10621 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)
10623 static msurface_t surface;
10624 const msurface_t *surfacelist = &surface;
10626 // fake enough texture and surface state to render this geometry
10627 surface.texture = texture;
10628 surface.num_triangles = numtriangles;
10629 surface.num_firsttriangle = firsttriangle;
10630 surface.num_vertices = numvertices;
10631 surface.num_firstvertex = firstvertex;
10634 rsurface.texture = R_GetCurrentTexture(surface.texture);
10635 rsurface.lightmaptexture = NULL;
10636 rsurface.deluxemaptexture = NULL;
10637 rsurface.uselightmaptexture = false;
10638 R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);